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

C# 如何使用鼠标滚轮使DataGridView一次滚动一个项目?,c#,.net,datagridview,C#,.net,Datagridview,我们希望在将鼠标滚轮与此控件一起使用时覆盖DataGridView的默认行为。默认情况下,DataGridView滚动的行数等于SystemInformation.MouseWheelScrollLines设置。我们要做的是一次只滚动一个项目 (我们在DataGridView中显示图像,图像有点大。因此,滚动三行(典型的系统设置)太多,通常会导致用户滚动到他们甚至看不到的项目。) 我已经试过几次了,到目前为止还没有成功。以下是我遇到的一些问题: 您可以订阅MouseWheel事件,但无法将事件标

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

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

我已经试过几次了,到目前为止还没有成功。以下是我遇到的一些问题:

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

  • 您可以覆盖OnMouseWheel,但它似乎从未被调用

  • 您可以在基本滚动代码中纠正这一点,但这听起来像是一个混乱的工作,因为其他类型的滚动(例如,使用键盘)都是通过相同的管道进行的

  • 有人有好的建议吗

    下面是最后的代码,使用给出的精彩答案:

        /// <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);
        }
    
    //
    ///由于我们显示
    ///图像,当您滚动多个图像时,这些图像无法正常工作
    ///一次一个项目。
    /// 
    /// 
    /// 
    ///寄件人
    /// 
    /// 
    ///鼠标事件
    /// 
    私有void mImageDataGrid_鼠标滚轮(对象发送器,鼠标指针e)
    {
    //黑客警报!通过反思,我们知道
    //in-event参数实际上是一个已处理的鼠标事件参数,
    //让我们自己来处理这件事。
    //看http://tinyurl.com/54o7lc 更多信息。
    HandledMouseEventArgs handledE=(HandledMouseEventArgs)e;
    handledE.Handled=true;
    //手动滚动。一次只移动一行。
    int rowIndex=mImageDataGrid.FirstDisplayedScrollingRowIndex;
    mImageDataGrid.FirstDisplayedScrollingRowIndex=
    e、 δ<0?
    Math.Min(行索引+1,mImageDataGrid.RowCount-1):
    Max(rowIndex-1,0);
    }
    
    我会将DataGridView子类化为我自己的自定义控件(您知道,添加一个新的Windows窗体-->自定义控件文件,并将基类从control更改为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设置为超出网格范围的数字,等等。但这非常有效


    Richard

    覆盖onmouseheel而不调用base.onmouseheel应该可以工作。某些滚轮鼠标具有特殊设置,您可能需要自行设置才能使其正常工作。请看这篇文章

    我只是自己做了一些搜索和测试。我曾经调查并发现了一些事情。
    MouseWheel
    事件提供了一个
    MouseEventArgs
    参数,但是
    DataGridView
    中的
    OnMouseWheel()
    覆盖将其强制转换为
    已处理的
    。这在处理
    鼠标滚轮
    事件时也起作用
    OnMouseWheel()
    确实会被调用,并且它在
    DataGridView
    的覆盖中使用了
    SystemInformation.MouseWheelScrollLines

    因此:

  • 您确实可以处理
    MouseWheel
    事件,将
    MouseEventArgs
    强制转换为
    HandledMouseEventArgs
    并设置
    Handled=true
    ,然后执行所需操作

  • 子类
    DataGridView
    ,重写
    onmouseheel()
    您自己,并尝试重新创建我在此处阅读的所有代码,除了用
    1
    替换
    SystemInformation.mouseheelScrollLines


  • 后者将是一个巨大的痛苦,因为它使用了许多私有变量(包括对
    滚动条的引用),您必须用自己的替换一些,并使用反射获取/设置其他变量。

    更新:,因为我现在了解到
    DataGridView
    有一个
    鼠标滚轮事件,我添加了第二个更简单的覆盖

    实现这一点的一种方法是对
    DataGridView
    进行子类化,并覆盖
    WndProc
    ,以添加对
    WM\u mouseweel
    消息的特殊处理

    此示例捕获鼠标滚轮的移动,并将其替换为调用
    SendKeys.Send

    (这与滚动略有不同,因为它还选择了
    DataGridView
    的下一行/上一行。但它可以工作。)

    公共类MyDataGridView:DataGridView { 私人建筑WM_鼠标轮=0x20a; 受保护的覆盖无效WndProc(参考消息m) { 如果(m.Msg==WM_鼠标轮) { var wheelDelta=((int)m.WParam)>>16; 如果(车轮三角洲<0) { SendKeys.Send(“{DOWN}”); } 如果(车轮三角洲>0) { SendKeys.Send(“{UP}”); } 返回; } 基准WndProc(参考m); } }
    第二步(与上述注意事项相同):

    公共类MyDataGridView:DataGridView { MouseWheel上的受保护覆盖无效(MouseEventArgs e) { 如果(e.Delta<0) SendKeys.Send(“{DOWN}”); 其他的 SendKeys.Send(“{UP}”); } }
    我确实提到了这一点,但我做错了什么。我认为这会起作用(假设有人做得正确!)。谢谢。我认为这是可行的,尽管我选择的答案更简单。
    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);
        }
    }
    
    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}");
        }
    }