¿Cómo se puede hacer un DataGridView desplazar un elemento a la vez usando la rueda del mouse?

StackOverflow https://stackoverflow.com/questions/135105

  •  02-07-2019
  •  | 
  •  

Pregunta

Nos gustaría anular el comportamiento predeterminado de DataGridView cuando se usa una rueda del mouse con este control. De forma predeterminada, el DataGridView desplaza un número de filas igual a la configuración SystemInformation.MouseWheelScrollLines. Lo que nos gustaría hacer es desplazar solo un elemento a la vez.

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

Ya probé un par de cosas y hasta ahora no he tenido mucho éxito. Aquí hay algunos problemas que he encontrado:

  1. Puedes suscribirte a los eventos de MouseWheel, pero no hay forma de marcar el evento como manejado y hacer mis propias cosas.

  2. Puedes anular OnMouseWheel pero parece que nunca se llama.

  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, mediante el teclado) llegan a través de la misma canalización.

¿Alguien tiene una buena sugerencia?

Aquí está el código final, usando 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);
    }
¿Fue útil?

Solución

Acabo de hacer un poco de scrounging y pruebas por mi cuenta. Utilicé Reflector para investigar y descubrir un par de cosas. El evento MouseWheel proporciona un parámetro MouseEventArgs , pero el reemplazo OnMouseWheel () en DataGridView lo convierte en Handled MouseEventArgs . Esto también funciona cuando se maneja el evento MouseWheel . OnMouseWheel () sí se llama, y ??está en la anulación de DataGridView que utiliza SystemInformation.MouseWheelScrollLines .

Entonces:

  1. De hecho, podría controlar el evento MouseWheel , lanzando MouseEventArgs a HandledMouseEventArgs y establecer Handled = true , luego haz lo que quieras.

  2. Subclase DataGridView , anule OnMouseWheel () usted mismo, e intente recrear todo el código que leí aquí en Reflector a excepción de la sustitución de SystemInformation.MouseWheelScrollLines con 1 .

El último sería un gran dolor, ya que utiliza una serie de variables privadas (incluidas las referencias a las ScrollBar s) y deberías reemplazar algunas por las tuyas y obtener / configurar otras utilizando Reflection .

Otros consejos

Subclasificaré DataGridView en mi propio control personalizado (ya sabes, agregaré un nuevo formulario de formularios de Windows - > Control personalizado y cambiaré la clase base de Control a DataGridView).

public partial class MyDataGridView : DataGridView

Luego invalide el método WndProc y sustituya 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á la comprobación de que no establece FirstDisplayedScrollingRowIndex en un número fuera del rango de su cuadrícula, etc. ¡Pero esto funciona bastante bien!

Richard

Sobrescribir OnMouseWheel y no llamar a base.OnMouseWheel debería funcionar. Algunos ratones con rueda tienen una configuración especial que puede que necesite configurar para que funcione correctamente. Consulte esta publicación http://forums.microsoft.com/MSDN/ShowPost .aspx? PostID = 126295 & amp; SiteID = 1

ACTUALIZACIÓN: Desde que supe que DataGridView tiene un evento MouseWheel , agregué un segundo reemplazo más simple.

Una forma de lograr esto es subclasificar el DataGridView y anular el WndProc para agregar un manejo especial del WM_MOUSEWHEEL .

Este ejemplo atrapa el movimiento de la rueda del mouse y lo reemplaza con una llamada a SendKeys.Send .

(Esto es un poco diferente al desplazamiento, ya que también selecciona la fila siguiente / anterior de 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 que se mencionaron anteriormente):

public class MyDataGridView : DataGridView
{
    protected override void OnMouseWheel(MouseEventArgs e)
    {
        if (e.Delta < 0)
            SendKeys.Send("{DOWN}");
        else
            SendKeys.Send("{UP}");
    }
}
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top