如何在拖放过程中自动滚动 DataGridView [英] How To AutoScroll a DataGridView during Drag and Drop

查看:25
本文介绍了如何在拖放过程中自动滚动 DataGridView的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的 C# .NET 应用程序中的一个表单有多个 DataGridViews,它们实现拖放以移动行.拖放大部分工作正常,但我一直很难让 DataGridViews 到 AutoScroll - 当一行被拖动到框的顶部或底部附近时,向那个方向滚动.

One of the forms in my C# .NET application has multiple DataGridViews that implement drag and drop to move the rows around. The drag and drop mostly works right, but I've been having a hard time getting the DataGridViews to AutoScroll - when a row is dragged near the top or bottom of the box, to scroll it in that direction.

到目前为止,我已经尝试实现一个版本的 这个 解决方案.我有一个继承自 DataGridView 的 ScrollingGridView 类,它实现了所描述的计时器,并且根据调试器,计时器正在适当地触发,但是计时器代码:

So far, I've tried implementing a version of this solution. I have a ScrollingGridView class inheriting from DataGridView that implements the described timer, and according to the debugger, the timer is firing appropriately, but the timer code:

const int WM_VSCROLL = 277;
private static extern int SendMessage(IntPtr hWnd, int wMsg, IntPtr wParam, IntPtr lParam);

private void ScrollingGridViewTimerTick(object sender, EventArgs e)
{
    SendMessage(Handle, WM_VSCROLL, (IntPtr)scrollDirectionInt, IntPtr.Zero);
}

据我所知没有做任何事情,可能是因为我在表单中有多个 DataGridView.我也尝试修改 AutoScrollOffset 属性,但这也没有做任何事情.对 DataGridView 和 ScrollBar 类的调查似乎没有建议任何其他命令或函数实际上会使 DataGridView 滚动.任何人都可以帮助我使用实际滚动 DataGridView 的功能,或其他解决问题的方法吗?

doesn't do anything as far as I can tell, possibly because I have multiple DataGridViews in the form. I also tried modifying the AutoScrollOffset property, but that didn't do anything either. Investigation of the DataGridView and ScrollBar classes doesn't seem to suggest any other commands or functions that will actually make the DataGridView scroll. Can anyone help me with a function that will actually scroll the DataGridView, or some other way to solve the problem?

推荐答案

我有一段时间没看这段代码了.但不久前我实现了一个支持这个的 DataGridView.

I haven't looked at this code in a while. But a while back I implemented a DataGridView that supported just this.

    class DragOrderedDataGridView : System.Windows.Forms.DataGridView
{
    public delegate void RowDroppedEventHangler(object source, DataGridViewRow sourceRow, DataGridViewRow destinationRow);
    public event RowDroppedEventHangler RowDropped;

    bool bDragging = false;
    System.Windows.Forms.DataGridView.HitTestInfo hti = null;
    System.Threading.Timer scrollTimer = null;
    delegate void SetScrollDelegate(int value);

    public bool AllowDragOrdering { get; set; }

    protected override void OnMouseDown(System.Windows.Forms.MouseEventArgs e)
    {
        if (AllowDragOrdering)
        {
            DataGridView.HitTestInfo hti = this.HitTest(e.X, e.Y);

            if (hti.RowIndex != -1
             && hti.RowIndex != this.NewRowIndex
             && e.Button == MouseButtons.Left)
            {
                bDragging = true;
            }
        }

        base.OnMouseDown(e);
    }

    protected override void OnMouseMove(System.Windows.Forms.MouseEventArgs e)
    {
        if (bDragging && e.Button == MouseButtons.Left)
        {
            DataGridView.HitTestInfo newhti = this.HitTest(e.X, e.Y);
            if (hti != null && hti.RowIndex != newhti.RowIndex)
            {
                System.Diagnostics.Debug.WriteLine("invalidating " + hti.RowIndex.ToString());
                Invalidate();
            }
            hti = newhti;
            System.Diagnostics.Debug.WriteLine(string.Format("{0:000} {1}  ", hti.RowIndex, e.Location));

            Point clientPoint = this.PointToClient(e.Location);


            System.Diagnostics.Debug.WriteLine(e.Location + "  " + this.Bounds.Size);
            if (scrollTimer == null
            && ShouldScrollDown(e.Location))
            {
                //
                // enable the timer to scroll the screen
                //
                scrollTimer = new System.Threading.Timer(new System.Threading.TimerCallback(TimerScroll), 1, 0, 250);
            }
            if (scrollTimer == null
            && ShouldScrollUp(e.Location))
            {
                scrollTimer = new System.Threading.Timer(new System.Threading.TimerCallback(TimerScroll), -1, 0, 250);
            }

        }
        else
        {
            bDragging = false;
        }

        if (!(ShouldScrollUp(e.Location) || ShouldScrollDown(e.Location)))
        {
            StopAutoScrolling();
        }
        base.OnMouseMove(e);
    }

    bool ShouldScrollUp(Point location)
    {
        return location.Y > this.ColumnHeadersHeight
            && location.Y < this.ColumnHeadersHeight + 15
            && location.X >= 0
            && location.X <= this.Bounds.Width;
    }

    bool ShouldScrollDown(Point location)
    {
        return location.Y > this.Bounds.Height - 15
            && location.Y < this.Bounds.Height
            && location.X >= 0
            && location.X <= this.Bounds.Width;
    }

    void StopAutoScrolling()
    {
        if (scrollTimer != null)
        {
            //
            // disable the timer to scroll the screen
            // 
            scrollTimer.Change(System.Threading.Timeout.Infinite, System.Threading.Timeout.Infinite);
            scrollTimer = null;
        }
    }

    void TimerScroll(object state)
    {
        SetScrollBar((int)state);
    }

    bool scrolling = false;

    void SetScrollBar(int direction)
    {
        if (scrolling)
        {
            return;
        }
        if (this.InvokeRequired)
        {
            this.Invoke(new Action<int>(SetScrollBar), new object[] {direction});
        }
        else
        {
            scrolling = true;

            if (0 < direction)
            {
                if (this.FirstDisplayedScrollingRowIndex < this.Rows.Count - 1)
                {
                    this.FirstDisplayedScrollingRowIndex++;
                }
            }
            else
            {
                if (this.FirstDisplayedScrollingRowIndex > 0)
                {
                    this.FirstDisplayedScrollingRowIndex--;
                }
            }

            scrolling = false;
        }

    }



    protected override void OnMouseUp(System.Windows.Forms.MouseEventArgs e)
    {
        bDragging = false;
        HitTestInfo livehti = hti;
        hti = null;

        if (RowDropped != null
         && livehti != null
         && livehti.RowIndex != -1
         && this.CurrentRow.Index != livehti.RowIndex)
        {
            RowDropped(this, this.CurrentRow, this.Rows[livehti.RowIndex]);
        }
        StopAutoScrolling();

        Invalidate();
        base.OnMouseUp(e);
    }

    protected override void OnCellPainting(System.Windows.Forms.DataGridViewCellPaintingEventArgs e)
    {
        if (bDragging && hti != null && hti.RowIndex != -1
         && e.RowIndex == hti.RowIndex)
        {
            //
            // draw the indicator
            //
            Pen p = new Pen(Color.FromArgb(0, 0, 215));
            p.Width = 4;
            e.Graphics.DrawLine(p, e.CellBounds.Left, e.CellBounds.Top, e.CellBounds.Right, e.CellBounds.Top);
        }

        base.OnCellPainting(e);
    }
}

这篇关于如何在拖放过程中自动滚动 DataGridView的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆