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

问题描述 投票:0回答:5

我们希望在使用鼠标滚轮与此控件时覆盖 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);
    }
c# .net datagridview
5个回答
4
投票

我只是自己做了一些搜索和测试。我使用 Reflector 进行调查并发现了一些事情。

MouseWheel
事件提供了
MouseEventArgs
参数,但
OnMouseWheel()
中的
DataGridView
覆盖将其转换为
Handled
MouseEventArgs
。这在处理
MouseWheel
事件时也适用。
OnMouseWheel()
确实被调用,并且它在
DataGridView
的覆盖中使用了
SystemInformation.MouseWheelScrollLines

所以:

  1. 您确实可以处理

    MouseWheel
    事件,将
    MouseEventArgs
    转换为
    HandledMouseEventArgs
    并设置
    Handled = true
    ,然后执行您想要的操作。

  2. 子类

    DataGridView
    ,自己覆盖
    OnMouseWheel()
    ,并尝试重新创建我在Reflector中阅读的所有代码,除了用
    SystemInformation.MouseWheelScrollLines
    替换
    1

后者将是一个巨大的痛苦,因为它使用了许多私有变量(包括对

ScrollBar
的引用),并且您需要用自己的变量替换一些变量,并使用反射获取/设置其他变量。


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 设置为网格范围之外的数字等。但这非常有效!

理查德


1
投票

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


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

0
投票

我知道我迟到了 15 年,但我发现这个解决方案可以完美地工作,并且没有此线程中其他解决方案似乎遇到的警告。

protected override void OnMouseWheel(MouseEventArgs e)
{
    if (e.Delta > 0)
    {
        if (FirstDisplayedScrollingRowIndex > 0)
        {
            FirstDisplayedScrollingRowIndex--;
        }
    }
    else
    {
        if (FirstDisplayedScrollingRowIndex < Rows.Count - 1)
        {
            FirstDisplayedScrollingRowIndex++;
        }
    }
}

尽管代码非常简单,但请检查您是否在有效范围内,并相应地更改

FirstDisplayedScrollingRowIndex

© www.soinside.com 2019 - 2024. All rights reserved.