We'd like to override DataGridView's default behavior when using a mouse wheel with this control. By default, the DataGridView scrolls a number of rows equal the SystemInformation.MouseWheelScrollLines setting. What we'd like to do is scroll just one item at a time.
(We display images in the DataGridView, which are somewhat large. Because of this scroll three rows (a typical system setting) is too much, often causing the user to scroll to items they can't even see.)
I've tried a couple things already and haven't had much success so far. Here are some issues I've run into:
You can subscribe to MouseWheel events but there's no way to mark the event as handled and do my own thing.
You can override OnMouseWheel but this never appears to be called.
You might be able to correct this in the base scrolling code but it sounds like a messy job since other types of scrolling (e.g. using the keyboard) come through the same pipeline.
Anyone have a good suggestion?
Here's the final code, using the wonderful answer given:
/// <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);
}