Как заставить DataGridView прокручивать один элемент за раз с помощью колеса мыши?
-
02-07-2019 - |
Вопрос
Мы хотели бы переопределить поведение 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);
}
Решение
Я просто немного поискал и протестировал сам.я использовал Отражатель чтобы исследовать и обнаружил пару вещей.А MouseWheel
мероприятие обеспечивает MouseEventArgs
параметр, но OnMouseWheel()
переопределить в DataGridView
бросает это на Handled
MouseEventArgs
.Это также работает при обработке MouseWheel
событие. OnMouseWheel()
действительно вызывается, и он находится в DataGridView
's переопределить, что он использует SystemInformation.MouseWheelScrollLines
.
Так:
Вы действительно могли бы справиться с
MouseWheel
мероприятие, кастингMouseEventArgs
кHandledMouseEventArgs
и установитьHandled = true
, тогда делай, что хочешь.Подкласс
DataGridView
, переопределитьOnMouseWheel()
самостоятельно и попытаться воссоздать весь код, который я прочитал здесь в Отражатель кроме заменыSystemInformation.MouseWheelScrollLines
с1
.
Последнее было бы огромной проблемой, поскольку оно использует ряд частных переменных (включая ссылки на ScrollBar
s), и вам придется заменить некоторые из них своими собственными и получить/установить другие с помощью Reflection.
Другие советы
Я бы подклассифицировал DataGridView в свой собственный пользовательский элемент управления (вы знаете, добавьте новый файл Windows Forms -> Custom Control и измените базовый класс с 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
event, я добавил второе, более простое переопределение.
Один из способов добиться этого — создать подкласс 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);
}
}
2-й дубль (с теми же оговорками, что упоминались выше):
public class MyDataGridView : DataGridView
{
protected override void OnMouseWheel(MouseEventArgs e)
{
if (e.Delta < 0)
SendKeys.Send("{DOWN}");
else
SendKeys.Send("{UP}");
}
}