2008-09-25 1 views
7

Мы хотели бы переопределить поведение DataGridView по умолчанию при использовании колеса мыши с этим элементом управления. По умолчанию DataGridView прокручивает ряд строк, равный настройке SystemInformation.MouseWheelScrollLines. То, что мы хотели бы сделать, это прокрутить только один элемент за раз.Как вы можете сделать DataGridView прокруткой одного элемента за раз с помощью колеса мыши?

(Мы показываем изображения в 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); 
    } 

ответ

4

Я просто немного подшутил и испытал свои собственные. Я использовал Reflector, чтобы исследовать и обнаружить пару вещей. Событие MouseWheel предоставляет параметр MouseEventArgs, но переопределение OnMouseWheel() в DataGridView отличает его от HandledMouseEventArgs. Это также работает при обработке события MouseWheel. OnMouseWheel() действительно вызван, и он находится в DataGridView, чтобы использовать его, используя SystemInformation.MouseWheelScrollLines.

Итак:

  1. Вы могли действительно обрабатывать MouseWheel событие, отбрасывая MouseEventArgs к HandledMouseEventArgs и установить Handled = true, а затем делать то, что вы хотите.

  2. Подкласс DataGridView, переопределяют OnMouseWheel() себя и попытаться воссоздать весь код, я прочитал здесь в Reflector для замены SystemInformation.MouseWheelScrollLines с 1 исключением.

Последнее было бы огромной болью, потому что она использует ряд частных переменных (в том числе ссылки на ScrollBar с), и вы должны были бы заменить некоторые с вашей собственной и получить/установить другие с помощью отражения.

1

Я бы подкласс DataGridView в мой собственный пользовательский элемент управления (вы знаете, добавить новый Windows Forms -> файл пользовательского управления и изменить базовый класс от 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 в число вне диапазона вашего сетка и т. д. Но это работает очень хорошо!

Ричард

+0

Спасибо. Я думаю, что это сработает, хотя ответ, который я выбираю, был проще. – 2008-09-25 20:44:25

1

Перекрытие OnMouseWheel и не требующие base.OnMouseWheel должны работать. У некоторых колесных мышей есть специальные настройки, которые вам могут потребоваться, чтобы он работал правильно. См. Этот пост http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=126295&SiteID=1

+0

Я упоминал об этом, но я делал что-то неправильно. Я думаю, что это сработает (если кто-то сделает это правильно!). – 2008-09-25 20:43:46

1

UPDATE: Так как я в настоящее время стало известно, что 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}"); 
    } 
} 
Смежные вопросы