2010-04-02 30 views
4

我的C#.NET應用程序中的一種形式具有多個DataGridView,它們實現拖放以移動行。拖放大部分工作正常,但我一直很難得到DataGridViews到AutoScroll - 當一行被拖動到框的頂部或底部附近時,以此方向滾動它。如何在拖放過程中自動滾動DataGridView

到目前爲止,我已嘗試實施this解決方案的一個版本。我有一個ScrollingGridView類從實現所述定時器的DataGridView繼承,並根據調試器,定時器被適當地射擊,但定時器代碼:

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); 
} 

不這樣做,據我可以告訴什麼,可能是因爲我在窗體中有多個DataGridViews。我也嘗試修改AutoScrollOffset屬性,但那也沒有做任何事。 DataGridView和ScrollBar類的調查似乎沒有建議任何其他命令或功能,實際上將使DataGridView滾動。任何人都可以幫助我一個實際上會滾動DataGridView的函數,或者其他解決問題的方法嗎?

+0

好像我們正在研究同樣的問題;一個能夠拖放行的datagridview – 2010-04-02 17:45:53

+0

@Mason:對不起,請參閱我的新工作解決方案的答案。 – 2010-04-05 14:36:18

+0

謝謝,夥計們。看起來這兩個解決方案的工作,但我標記this.FirstDisplayedScrollingRowIndex ++之一被接受,因爲它似乎更容易維護,而不是拉入一個DLL併發送一個記錄不好的Windows消息。但是,如果有人想以任何理由這樣做,那麼傳遞VerticalScrollBar.Handle作爲第四個參數是它的工作原理。 – Mason 2010-04-05 16:33:38

回答

1

我還沒有看過這段代碼。但是一段時間後,我實現了一個支持這個的DataGridView。

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); 
    } 
} 
+0

這麼簡單的任務代碼。 'MouseMove' - >'Button = MouseButton.Left' - >'IF(MousePosition.Y> dgv.Heigth的75% - >'dgv.Scroll + 5 lines',反之亦然'<25%'。通過這種方式,您可以在頂部和底部將1/4大小的「DataGridView」虛擬字段自動滾動。 – C4u 2016-07-26 15:44:14

1

感謝您對我的問題的幫助,或許我可以幫助您解決您的問題。

this頁:

[DllImport("user32.dll", CharSet = CharSet.Auto)] 
private static extern int SendMessage(IntPtr hWnd, int wMsg, IntPtr wParam, IntPtr lParam); 

//winuser.h constants 
private const int WM_VSCROLL = 277; // Vertical scroll 
private const int SB_LINEUP = 0; // Scrolls one line up 
private const int SB_LINEDOWN = 1; // Scrolls one line down 
private const int SB_ENDSCROLL = 8; // Ends the scrolling 

//Call this when you want to scroll 
private void ScrollGridview(int direction) 
{ 
    SendMessage(Handle, WM_VSCROLL, (IntPtr)direction, VerticalScrollBar.Handle); 
    SendMessage(Handle, WM_VSCROLL, (IntPtr)SB_ENDSCROLL, VerticalScrollBar.Handle); 
} 

(第二SendMessage似乎沒有必要,但我把它的好辦法)

我寫這既包括 此DataGridView控件 gbogumil的autoscroll解決方案和正確運行的OnPaint突出顯示 - 您可以找到它here

我想指出this control,我剛剛從另一個線程發現。它看起來非常好,但不幸的是它是GPL,因此您只能將它用於GPL項目。儘管如此,它可以完成我們所需要的所有工作,並提供更多功能

+0

沒問題。在調用SendMessage之前,我通過在句柄上調用FromHandle來檢查出結果,並在調試器中查看結果。這絕對是我的DataGridView的句柄,但SendMessage仍然沒有效果。 我會檢查出ObjectListView。我認爲這很好,因爲我們的應用程序僅供內部使用,但我寧願找到並抓取適當的塊,而不是重新設計一個新類。 – Mason 2010-04-02 20:20:38