2008-09-25 14 views
7

Nos gustaría sobrescribir el comportamiento predeterminado de DataGridView al usar una rueda del mouse con este control. De forma predeterminada, DataGridView desplaza una cantidad de filas igual a la configuración de SystemInformation.MouseWheelScrollLines. Lo que nos gustaría hacer es desplazar solo un elemento a la vez.¿Cómo se puede hacer que un DataGridView desplace un elemento a la vez con la rueda del mouse?

(Mostramos imágenes en el DataGridView, que son algo grandes. Debido a este desplazamiento tres filas (una configuración de sistema típica) es demasiado, lo que hace que el usuario se desplace a elementos que ni siquiera puede ver)

Ya he intentado un par de cosas y hasta ahora no he tenido tanto éxito. Estos son algunos asuntos me he encontrado:

  1. puede suscribirse a eventos MouseWheel pero no hay manera de marcar el evento como se maneja y hacer mi propia cosa.

  2. Puede anular OnMouseWheel pero esto nunca parece ser llamado.

  3. Es posible que pueda corregir esto en el código de desplazamiento de la base pero suena como un trabajo desordenado ya que otros tipos de desplazamiento (por ejemplo, usar el teclado) vienen a través de la misma tubería.

¿Alguien tiene una buena sugerencia?

Aquí está el código final, utilizando la maravillosa respuesta dada:

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

Respuesta

4

Acabo de hacer un pequeño scrounging y probar el mío. Usé Reflector para investigar y descubrí un par de cosas. El evento MouseWheel proporciona un parámetro MouseEventArgs, pero la anulación OnMouseWheel() en DataGridView lo arroja al HandledMouseEventArgs. Esto también funciona cuando se maneja el evento MouseWheel. OnMouseWheel() de hecho recibe una llamada, y está en la anulación DataGridView que usa SystemInformation.MouseWheelScrollLines.

Así:

  1. Usted puede controlar el evento en efecto MouseWheel, fundición MouseEventArgs-HandledMouseEventArgs y establecer Handled = true, a continuación, hacer lo que quiera.

  2. Subclase DataGridView, anulan OnMouseWheel() mismo, y tratar de recrear todo el código que leí aquí en Reflector excepto por la sustitución de SystemInformation.MouseWheelScrollLines con 1.

Este último sería un dolor enorme, ya que utiliza una serie de variables privadas (incluyendo referencias a los ScrollBar s) y usted tendría que reemplazar algunas de ellas con su propio y obtener/set otros que utilizan la reflexión.

1

Me subclase el DataGridView en mi propio control personalizado (ya saben, añadir un nuevo Windows Forms -> archivo de control personalizado y cambiar el clase base de Control a DataGridView).

public partial class MyDataGridView : DataGridView 

A continuación, reemplazar el método WndProc y substituir algo así:

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

Por supuesto, tendrá el cheque que no se establece FirstDisplayedScrollingRowIndex a un número fuera del alcance de su cuadrícula, etc. ¡Pero esto funciona bastante bien!

Richard

+0

Gracias. Creo que esto funcionaría, aunque la respuesta que elijo era más simple. –

1

Anulación OnMouseWheel y no base.OnMouseWheel que llaman deben trabajar. Algunos mouse de rueda tienen una configuración especial que puede necesitar para configurarse para que funcione correctamente. Ver esta publicación http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=126295&SiteID=1

+0

Mencioné esto pero estaba haciendo algo mal. Creo que esto funcionaría (¡suponiendo que alguien lo hiciera correctamente!). –

1

ACTUALIZACIÓN: Desde ahora he aprendido que el DataGridView tiene un evento MouseWheel, he añadido una segunda anulación, más simple.

Una forma de lograr esto es subclase el DataGridView y anule el WndProc para agregar un manejo especial del mensaje WM_MOUSEWHEEL.

Este ejemplo capta el movimiento de la rueda del mouse y la reemplaza con una llamada al SendKeys.Send.

(Esto es un poco diferente que sólo el desplazamiento, ya que también selecciona la fila siguiente/anterior del DataGridView. Pero funciona.)

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

segunda toma (con las mismas advertencias como se ha mencionado arriba):

public class MyDataGridView : DataGridView 
{ 
    protected override void OnMouseWheel(MouseEventArgs e) 
    { 
     if (e.Delta < 0) 
      SendKeys.Send("{DOWN}"); 
     else 
      SendKeys.Send("{UP}"); 
    } 
} 
Cuestiones relacionadas