Comment faire défiler un élément de DataGridView à la fois à l'aide de la molette de la souris?

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

  •  02-07-2019
  •  | 
  •  

Question

Nous aimerions remplacer le comportement par défaut de DataGridView lors de l'utilisation d'une molette de la souris avec ce contrôle. Par défaut, DataGridView fait défiler un nombre de lignes égal au paramètre SystemInformation.MouseWheelScrollLines. Ce que nous aimerions faire, c'est faire défiler un élément à la fois.

(Nous affichons dans le DataGridView des images qui sont un peu volumineuses. En raison de ce défilement, trois lignes (un paramètre système typique) est trop, ce qui amène souvent l'utilisateur à faire défiler les éléments qu'il ne peut même pas voir.)

J'ai déjà essayé plusieurs choses et je n'ai pas eu beaucoup de succès jusqu'à présent. Voici quelques problèmes que j'ai rencontrés:

  1. Vous pouvez vous abonner à des événements MouseWheel mais vous ne pouvez pas marquer l'événement comme étant géré et faire ce que je veux.

  2. Vous pouvez remplacer OnMouseWheel mais cela ne semble jamais être appelé.

  3. Vous pourrez peut-être corriger cela dans le code de défilement de base, mais cela semble être un travail fastidieux, car d'autres types de défilement (par exemple, au clavier) passent par le même pipeline.

Quelqu'un a-t-il une bonne suggestion?

Voici le code final, en utilisant la merveilleuse réponse donnée:

    /// <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);
    }
Était-ce utile?

La solution

Je viens juste de fouiller un peu et d’essayer moi-même. J'ai utilisé Reflector pour enquêter et découvrir deux choses. L'événement MouseWheel fournit un paramètre MouseEventArgs , mais le remplacement de OnMouseWheel () dans DataGridView le transfère vers . Géré MouseEventArgs . Cela fonctionne également lors de la gestion de l'événement MouseWheel . OnMouseWheel () est effectivement appelé et c’est dans la substitution de DataGridView qu’il utilise SystemInformation.MouseWheelScrollLines .

Donc:

  1. Vous pouvez en effet gérer l'événement MouseWheel , en convertissant MouseEventArgs en HandledMouseEventArgs et en définissant Handled = true puis faites ce que vous voulez.

  2. Sous-classe DataGridView , remplacez vous-même OnMouseWheel () et essayez de recréer tout le code que j'ai lu ici dans Reflector sauf pour remplacer SystemInformation.MouseWheelScrollLines par 1 .

Ce dernier serait très pénible car il utilise un certain nombre de variables privées (y compris des références aux ScrollBar s) et vous devez en remplacer certaines par les vôtres et en obtenir / définir d’autres à l’aide de Reflection. .

Autres conseils

Je voudrais sous-classer DataGridView dans mon propre contrôle personnalisé (vous savez, ajouter un nouveau fichier Windows Forms - > Contrôle personnalisé et modifier la classe de base de Control à DataGridView).

public partial class MyDataGridView : DataGridView

Redéfinissez ensuite la méthode WndProc et remplacez-la de la manière suivante:

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

Bien sûr, vous aurez la possibilité de ne pas définir FirstDisplayedScrollingRowIndex sur un nombre en dehors de la plage de votre grille, etc. Mais cela fonctionne très bien!

Richard

Remplacer OnMouseWheel et ne pas appeler base.OnMouseWheel devrait fonctionner. Certaines souris à molette ont des réglages spéciaux que vous devrez peut-être définir vous-même pour que cela fonctionne correctement. Voir ce message http://forums.microsoft.com/MSDN/ShowPost .aspx? PostID = 126295 & SiteID = 1

UPDATE: Depuis que je sais maintenant que DataGridView a un événement MouseWheel , j'ai ajouté un deuxième remplacement plus simple.

Pour ce faire, vous pouvez sous-classer le DataGridView et remplacer le WndProc pour ajouter un traitement spécial du message WM_MOUSEWHEEL .

Cet exemple intercepte le mouvement de la molette de la souris et le remplace par un appel à SendKeys.Send .

(Cela diffère légèrement du défilement, car il sélectionne également la ligne suivante / précédente du DataGridView . Mais cela fonctionne.)

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

2e prise (avec les mêmes mises en garde que mentionnées ci-dessus):

public class MyDataGridView : DataGridView
{
    protected override void OnMouseWheel(MouseEventArgs e)
    {
        if (e.Delta < 0)
            SendKeys.Send("{DOWN}");
        else
            SendKeys.Send("{UP}");
    }
}
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top