[英]How can you make a DataGridView scroll one item at a time using the mouse wheel?
当使用具有此控件的鼠标滚轮时,我们想要覆盖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);
}
我只是对我自己进行了一些调查和测试。 我用Reflector调查并发现了几件事。 MouseWheel
事件提供MouseEventArgs
参数,但DataGridView
的OnMouseWheel()
重写将其强制转换为Handled
MouseEventArgs
。 这在处理MouseWheel
事件时也有效。 确实调用了OnMouseWheel()
,它在DataGridView
的覆盖中使用了SystemInformation.MouseWheelScrollLines
。
所以:
您确实可以处理MouseWheel
事件,将MouseEventArgs
为HandledMouseEventArgs
并设置Handled = true
,然后执行您想要的操作。
子类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.