2008-09-25 75 views
7

我們想在此控件中使用鼠標滾輪時重寫DataGridView的默認行爲。默認情況下,DataGridView滾動一些等於SystemInformation.MouseWheelScrollLines設置的行。我們想要做的是一次只滾動一個項目。我們在DataGridView中顯示的圖像有些大,因爲這種滾動三行(一個典型的系統設置)太多了,通常會導致用戶滾動到他們甚至看不到的項目。)如何讓DataGridView使用鼠標滾輪一次滾動一個項目?

我已經嘗試了幾件事情,迄今爲止還沒有取得太大的成功。這裏有一些問題,我碰到的:

  1. 您可以訂閱鼠標滾輪事件,但沒有辦法,以紀念事件的處理,做我自己的事情。

  2. 您可以重寫OnMouseWheel,但這似乎永遠不會被調用。

  3. 您可能可以在基本滾動代碼中更正此問題,但由於其他類型的滾動(例如,使用鍵盤)通過相同的管道傳遞,因此聽起來像是一團亂七八糟的工作。

任何人都有很好的建議嗎?

下面是最後的代碼,使用給出精彩的答案:

/// <summary> 
    /// Handle the mouse wheel manually due to the fact that we display 
    /// images, which don't work well when you scroll by more than one 
    /// item at a time. 
    /// </summary> 
    /// 
    /// <param name="sender"> 
    /// sender 
    /// </param> 
    /// <param name="e"> 
    /// the mouse event 
    /// </param> 
    private void mImageDataGrid_MouseWheel(object sender, MouseEventArgs e) 
    { 
     // Hack alert! Through reflection, we know that the passed 
     // in event argument is actually a handled mouse event argument, 
     // allowing us to handle this event ourselves. 
     // See http://tinyurl.com/54o7lc for more info. 
     HandledMouseEventArgs handledE = (HandledMouseEventArgs) e; 
     handledE.Handled = true; 

     // Do the scrolling manually. Move just one row at a time. 
     int rowIndex = mImageDataGrid.FirstDisplayedScrollingRowIndex; 
     mImageDataGrid.FirstDisplayedScrollingRowIndex = 
      e.Delta < 0 ? 
       Math.Min(rowIndex + 1, mImageDataGrid.RowCount - 1): 
       Math.Max(rowIndex - 1, 0); 
    } 

回答

4

我只是做了一些小小的檢查和測試。我用Reflector來調查和發現一些事情。 MouseWheel事件提供MouseEventArgs參數,但中的OnMouseWheel()覆蓋會將其轉換爲HandledMouseEventArgs。這在處理MouseWheel事件時也有效。 OnMouseWheel()確實被調用,它在DataGridView的覆蓋,它使用SystemInformation.MouseWheelScrollLines

所以:

  1. 你確實可以處理MouseWheel事件,鑄造MouseEventArgsHandledMouseEventArgs並設置Handled = true,然後做你想做的。

  2. 子類DataGridView,覆蓋OnMouseWheel()自己,並嘗試重新所有我讀到這裏Reflector除了與1更換SystemInformation.MouseWheelScrollLines的代碼。

後者將是一個巨大的痛苦,因爲它使用了一些私有變量(包括對ScrollBar S變量)和你有你自己的替換一些和獲取/設置其他使用反思。

1

我會繼承DataGridView的到我自己的自定義控制(你知道,添加一個新的Windows窗體 - >自定義控制文件,更改從Control到DataGridView的基類)。

public partial class MyDataGridView : DataGridView 

然後覆蓋WndProc方法和替代的東西,像這樣:

protected override void WndProc(ref Message m) 
{ 
    if (m.Msg == 0x20a) 
    { 
     int wheelDelta = ((int)m.WParam) >> 16; 

     // 120 = UP 1 tick 
     // -120 = DOWN 1 tick 

     this.FirstDisplayedScrollingRowIndex -= (wheelDelta/120); 
    } 
    else 
    { 
     base.WndProc(ref m); 
    } 
} 

當然,你有你不設置FirstDisplayedScrollingRowIndex到數字的範圍外的檢查你的網格等,但這工作得很好!

理查德

+0

謝謝。我認爲這會起作用,儘管我選擇的答案更簡單。 – 2008-09-25 20:44:25

1

UPDATE:既然我現在已經瞭解到,DataGridViewMouseWheel事件,我添加了一個第二,簡單的覆蓋。

完成此操作的一種方法是繼承DataGridView並覆蓋WndProc以添加對WM_MOUSEWHEEL消息的特殊處理。

本示例捕獲鼠標滾輪移動,並用SendKeys.Send的呼叫代替它。如前所述

(這不僅僅是滾動有點不同,因爲它也選擇DataGridView下一/前一列,但它的工作原理。)

public class MyDataGridView : DataGridView 
{ 
    private const uint WM_MOUSEWHEEL = 0x20a; 

    protected override void WndProc(ref Message m) 
    { 
     if (m.Msg == WM_MOUSEWHEEL) 
     { 
      var wheelDelta = ((int)m.WParam) >> 16; 

      if (wheelDelta < 0) 
      { 
       SendKeys.Send("{DOWN}"); 
      } 

      if (wheelDelta > 0) 
      { 
       SendKeys.Send("{UP}"); 
      } 

      return; 
     } 

     base.WndProc(ref m); 
    } 
} 

第二取(用相同的警告以上):

public class MyDataGridView : DataGridView 
{ 
    protected override void OnMouseWheel(MouseEventArgs e) 
    { 
     if (e.Delta < 0) 
      SendKeys.Send("{DOWN}"); 
     else 
      SendKeys.Send("{UP}"); 
    } 
} 
相關問題