簡體   English   中英

如何使用鼠標滾輪一次使DataGridView滾動一個項目?

[英]How can you make a DataGridView scroll one item at a time using the mouse wheel?

當使用具有此控件的鼠標滾輪時,我們想要覆蓋DataGridView的默認行為。 默認情況下,DataGridView滾動的行數等於SystemInformation.MouseWheelScrollLines設置。 我們想要做的是一次只滾動一個項目。

(我們在DataGridView中顯示圖像,它們有點大。由於這個滾動三行(典型的系統設置)太多,經常導致用戶滾動到他們甚至看不到的項目。)

我已經嘗試了幾件事,到目前為止還沒有取得多大成功。 以下是我遇到的一些問題:

  1. 您可以訂閱MouseWheel事件,但無法將事件標記為已處理並執行自己的操作。

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

我只是對我自己進行了一些調查和測試。 我用Reflector調查並發現了幾件事。 MouseWheel事件提供MouseEventArgs參數,但DataGridViewOnMouseWheel()重寫將其強制轉換為Handled MouseEventArgs 這在處理MouseWheel事件時也有效。 確實調用了OnMouseWheel() ,它在DataGridView的覆蓋中使用了SystemInformation.MouseWheelScrollLines

所以:

  1. 您確實可以處理MouseWheel事件,將MouseEventArgsHandledMouseEventArgs並設置Handled = true ,然后執行您想要的操作。

  2. 子類DataGridView ,自己重寫OnMouseWheel() ,並嘗試重新創建我在Reflector中讀到的所有代碼,除了用1替換SystemInformation.MouseWheelScrollLines

后者將是一個巨大的痛苦,因為它使用了許多私有變量(包括對ScrollBar的引用),你將用自己的替換一些,並使用Reflection獲取/設置其他變量。

我將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設置為網格范圍之外的數字等。但這樣做效果很好!

理查德

覆蓋OnMouseWheel而不是調用base.OnMouseWheel應該可以工作。 某些滾輪鼠標有特殊設置,您可能需要自行設置它才能正常工作。 請參閱此文章http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=126295&SiteID=1

更新:由於我現在已經知道DataGridView有一個MouseWheel事件,我添加了第二個更簡單的覆蓋。

實現此目的的一種方法是WndProc 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}");
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM