【问题标题】:How do I programmatically scroll a winforms datagridview control?如何以编程方式滚动 winforms datagridview 控件?
【发布时间】:2011-06-13 13:51:34
【问题描述】:

我在一个继承自datagridview 的控件中实现了一些拖放功能。基本上我是从 DGV 中的某个地方拖出一行并将其放到其他地方,重新排序行。我遇到了一个问题。如果 DGV 太大以至于有滚动条,我怎样才能让 DGV 在用户处于拖放中间时向上或向下滚动?

我知道如何获取当前鼠标位置以及获取 dgv 矩形等的位置。所以,我可以很容易地找出我是在矩形的上半部分还是下半部分……我只需要一种以编程方式滚动 dgv 的方法。如果我不必不断更改选定的单元格来执行此操作,我会更喜欢。

有什么建议吗?

谢谢

艾萨克

【问题讨论】:

    标签: winforms datagridview scroll


    【解决方案1】:

    您可以使用 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);
    

    现在假设您的表单上有一个文本框控件。您可以使用以下方式移动它:

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

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

    【讨论】:

    • 谢谢。我没试过..你上面的那个人有一个非winapi的方法。
    【解决方案2】:

    您可以通过设置HorizontalScrollingOffset / VerticalScrollingOffsetDataGridView 来做到这一点

    设置 Horizo​​ntalScrollingOffset

    dataGridView1.HorizontalScrollingOffset = dataGridView1.HorizontalScrollingOffset + 10;
    

    检查

    DataGridView.HorizontalScrollingOffset Property

    对于VerticalScrollingOffset,您可以使用反射

    包括命名空间System.Reflection

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

    【讨论】:

    • VerticalScrollingOffset 有只读属性。所以你只能get 它,不能set 它。
    • 不是两者,水平是 {get; set;} 虽然这对他没有任何帮助
    • o 没有注意到……所以对于 VerticalScrollingOffset,您可以用户反思……编辑我的代码……
    • 哇,我不知道你可以使用反射来绕过只读属性。这实际上滚动了控件。非常感谢!
    • 这似乎只是向上滚动。如何让它向下滚动?
    【解决方案3】:

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

    【讨论】:

    • 是的,我只需要弄清楚如何滚动一行!
    • 啊,下面这位大佬有办法。我已经实现了dragover,我将在其中添加一些代码,让它像你建议的那样智能地滚动。感谢您的设计建议 Hans。
    • 实际上,即使没有计时器,它也能正常工作!似乎鼠标下方网格行的移动足以继续触发 DragOver 事件。
    【解决方案4】:

    好吧,因为这是一个数据网格视图...抱歉问题中的“winforms”...但我可以这样做..向上或向下滚动一行。

    向上滚动:

    this.FirstDisplayedScrollingRowIndex = this.FirstDisplayedScrollingRowIndex - 1
    

    向下滚动:

    this.FirstDisplayedScrollingRowIndex = this.FirstDisplayedScrollingRowIndex + 1;
    

    您必须确保检查数字是否超出范围。

    【讨论】:

    • 当有很多隐藏行时("row[i].visible = false")。这行不通。 row+1, -1 将指向不可见的行,它什么也不做!!
    【解决方案5】:
    dgv.FirstDisplayedScrollingRowIndex = dgv.RowCount - 1;
    

    【讨论】:

      【解决方案6】:

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

      唯一的问题是有点装饰性的,如果你滚动得很快,第二个 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, 
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-07-04
        • 2017-04-13
        • 1970-01-01
        相关资源
        最近更新 更多