如何使用鼠标滚轮一次使DataGridView滚动一个项目?

时间:2008-09-25 18:33:07

标签: c# .net datagridview

当使用带有此控件的鼠标滚轮时,我们想要覆盖DataGridView的默认行为。默认情况下,DataGridView滚动的行数等于SystemInformation.MouseWheelScrollLines设置。我们想要做的是一次只滚动一个项目。

(我们在DataGridView中显示图像,它们有点大。由于这个滚动三行(典型的系统设置)太多,经常导致用户滚动到他们甚至看不到的项目。)

我已经尝试了几件事,到目前为止还没有取得多大成功。以下是我遇到的一些问题:

  1. 您可以订阅MouseWheel事件,但无法将事件标记为已处理并执行自己的操作。

  2. 您可以覆盖OnMouseWheel,但这似乎永远不会被调用。

  3. 您可以在基本滚动代码中更正此问题,但这听起来像是一个混乱的工作,因为其他类型的滚动(例如使用键盘)来自同一个管道。

  4. 有人有个好主意吗?

    这是最终的代码,使用了给出的精彩答案:

        /// <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 个答案:

答案 0 :(得分:4)

我只是对自己进行了一些调查和测试。我使用Reflector来调查并发现了一些事情。 MouseWheel事件提供了MouseEventArgs参数,但OnMouseWheel()中的DataGridView覆盖会将其转换为 Handled MouseEventArgs 。这在处理MouseWheel事件时也有效。 OnMouseWheel()确实被调用了,并且它在DataGridView的覆盖中使用了SystemInformation.MouseWheelScrollLines

所以:

  1. 您确实可以处理MouseWheel事件,将MouseEventArgs投射到HandledMouseEventArgs并设置Handled = true,然后执行您想要的操作。

  2. 子类DataGridView,自己覆盖OnMouseWheel(),并尝试重新创建我在Reflector中阅读的所有代码,只不过用{{1}替换SystemInformation.MouseWheelScrollLines }。

  3. 后者将是一个巨大的痛苦,因为它使用了许多私有变量(包括对1的引用)并且你已经用自己的变量替换了一些并使用Reflection获取/设置其他变量。

答案 1 :(得分:1)

我将DataGridView子类化为我自己的自定义控件(你知道,添加一个新的Windows窗体 - &gt;自定义控件文件,并将基类从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设置为网格范围之外的数字等。但这样做效果非常好!

理查德

答案 2 :(得分:1)

重写OnMouseWheel而不是调用base.OnMouseWheel应该可以工作。某些滚轮鼠标有特殊设置,您可能需要自行设置它才能正常工作。请参阅此帖子http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=126295&SiteID=1

答案 3 :(得分:1)

更新:由于我现在知道DataGridView有一个MouseWheel事件,我添加了第二个更简单的覆盖。

实现此目的的一种方法是继承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}");
    }
}