如何以编程方式滚动winforms datagridview控件?

如何以编程方式滚动winforms datagridview控件?,winforms,datagridview,scroll,Winforms,Datagridview,Scroll,我在继承自datagridview的控件中实现了一些拖放功能。基本上,我从DGV中的某个位置拖动一行,然后将其放到其他位置,重新排列行。不过我遇到了一个问题。如果DGV太大,以致有滚动条,那么当用户在拖拽的中间时,如何使DGV向上或向下滚动? 我知道如何获取当前鼠标位置,以及dgv矩形的位置等等。所以,我可以很容易地找出我是在矩形的上半部分还是下半部分。。。我只需要一种方式来编程滚动dgv。如果不必一直更改选定的单元格,我更愿意这样做 有什么建议吗 谢谢 Isaac您可以使用WinAPI向控件发

我在继承自datagridview的控件中实现了一些拖放功能。基本上,我从DGV中的某个位置拖动一行,然后将其放到其他位置,重新排列行。不过我遇到了一个问题。如果DGV太大,以致有滚动条,那么当用户在拖拽的中间时,如何使DGV向上或向下滚动?

我知道如何获取当前鼠标位置,以及dgv矩形的位置等等。所以,我可以很容易地找出我是在矩形的上半部分还是下半部分。。。我只需要一种方式来编程滚动dgv。如果不必一直更改选定的单元格,我更愿意这样做

有什么建议吗

谢谢


Isaac

您可以使用WinAPI向控件发送消息,告诉它向上或向下滚动

下面是代码,我希望它有帮助:

private const int WM_SCROLL = 276; // Horizontal scroll
private const int WM_VSCROLL = 277; // Vertical scroll
private const int SB_LINEUP = 0; // Scrolls one line up
private const int SB_LINELEFT = 0;// Scrolls one cell left
private const int SB_LINEDOWN = 1; // Scrolls one line down
private const int SB_LINERIGHT = 1;// Scrolls one cell right
private const int SB_PAGEUP = 2; // Scrolls one page up
private const int SB_PAGELEFT = 2;// Scrolls one page left
private const int SB_PAGEDOWN = 3; // Scrolls one page down
private const int SB_PAGERIGTH = 3; // Scrolls one page right
private const int SB_PAGETOP = 6; // Scrolls to the upper left
private const int SB_LEFT = 6; // Scrolls to the left
private const int SB_PAGEBOTTOM = 7; // Scrolls to the upper right
private const int SB_RIGHT = 7; // Scrolls to the right
private const int SB_ENDSCROLL = 8; // Ends scroll

[DllImport("user32.dll",CharSet=CharSet.Auto)]
private static extern int SendMessage(IntPtr hWnd, int wMsg,IntPtr wParam, IntPtr lParam);
现在假设表单上有一个textbox控件。您可以使用以下工具移动它:

SendMessage(textBox1.Handle,WM_VSCROLL,(IntPtr)SB_PAGEUP,IntPtr.Zero); //ScrollUp
SendMessage(textBox1.Handle,WM_VSCROLL,(IntPtr)SB_PAGEDOWN,IntPtr.Zero); //ScrollDown

如果经典的通用解决方案不适合你。您可能希望查看属性,并在拖动过程中根据鼠标位置对其进行更改。

您可以通过设置
DataGridView
HorizontalScrollingOffset
/
VerticalScrollingOffset
来完成此操作

设置水平滚动偏移的步骤

dataGridView1.HorizontalScrollingOffset = dataGridView1.HorizontalScrollingOffset + 10;
检查

对于垂直滚动偏移,可以使用反射

包括命名空间
System.Reflection

PropertyInfo verticalOffset = dataGridView1.GetType().GetProperty("VerticalOffset", BindingFlags.NonPublic | BindingFlags.Instance);
            verticalOffset.SetValue(this.dataGridView1, 10, null); 

您需要实现DragOver事件。检查鼠标是否靠近控件的顶部或底部(使用PointToClient)。如果是,启用间隔约200毫秒的计时器。在Tick事件处理程序中,将DGV滚动一行。当鼠标未关闭且DoDragDrop返回后,禁用计时器。用户现在可以轻松直观地滚动网格,只需将鼠标悬停在靠近端点的位置。

好吧,因为这是一个datagridview。。。很抱歉问题中的“winforms”。。。但我可以这么做。。向上或向下滚动一行

向上滚动:

this.FirstDisplayedScrollingRowIndex = this.FirstDisplayedScrollingRowIndex - 1
向下滚动:

this.FirstDisplayedScrollingRowIndex = this.FirstDisplayedScrollingRowIndex + 1;

不过,你必须确保数字没有超出范围。

以MaxEcho的答案为基础回答。您可以覆盖DataGridView的OnScroll事件。此方法中的EventArg包含第一个可见行号。您可以将此行号传递给另一个DataGridView,并设置FirstDisplayedScrollRowIndex以使其滚动到该位置

dgv.FirstDisplayedScrollingRowIndex = dgv.RowCount - 1;
唯一的问题有点表面化,如果滚动速度很快,第二个datagridview会暂停更新/设置动画,并在滚动速度减慢时闪烁到活动行

class DGVSubclass : DataGridView
{    

    public Action<ScrollEventArgs> delOnScroll;
    ....

    protected override void OnScroll(ScrollEventArgs e)
    {
        base.OnScroll(e);


        if (e.ScrollOrientation == ScrollOrientation.VerticalScroll && 
            delOnScroll != null)
            delOnScroll.Invoke(e);

    }

    public void setSrcoll(ScrollEventArgs e)
    {
        //ScrollEventArgs.NewValue is a line number
        this.FirstDisplayedScrollingRowIndex = e.NewValue;
    }

    public void bindScroll(DGV3_Broker dgv)
    {
        delOnScroll = dgv.setSrcoll;          
    }
}

dgvTwo.bindScroll(dgvOne);  //DGVTwo Scrollbar controls both, 
classdgvsubclass:DataGridView
{    
公共行动;
....
受保护的覆盖void OnScroll(ScrollEventArgs e)
{
base.OnScroll(e);
如果(e.ScrollOrientation==ScrollOrientation.VerticalScroll&&
delOnScroll!=null)
调用(e);
}
公共无效设置滚动(ScrollEventArgs e)
{
//ScrollEventArgs.NewValue是一个行号
this.FirstDisplayedScrollingRowIndex=e.NewValue;
}
公共无效绑定卷轴(DGV3_代理dgv)
{
delOnScroll=dgv.setSrcoll;
}
}
dgvTwo.bindcoll(dgvOne)//DGVTwo滚动条同时控制,

VerticalScrollingOffset具有只读属性。。所以你只能
get
it,不能
set
it。不是两者都是,Horizontal是{get;set;},虽然它在某种程度上对他没有帮助,但他没有注意到。。。所以对于垂直滚动偏移,您可以使用用户反射。。。编辑我的代码…哇,我不知道你可以使用反射来绕过只读属性。这实际上会滚动控件。非常感谢!这似乎只是向上滚动。我该如何使它向下滚动?是的,我只需要找出如何滚动一行!啊,下面的那位先生有办法。我已经实现了dragover,我将在其中添加一些代码,使它像您建议的那样智能地滚动。谢谢你的设计建议,汉斯。事实上,即使没有定时器,它也能正常工作!看起来鼠标下方网格行的移动足以持续触发DragOver事件。谢谢。我还没试过。。上面的人有一种非winapi的方法来实现这一点。当有很多隐藏行(“行[i].visible=false”)时。这是行不通的。行+1,-1将指向不可见行,该行将不起任何作用!!