Windows Forms - ScrollableControl
Par L'équipe Bewise, posté le 12/07/2010
Pour gérer le scrolling en Windows Forms vous avez deux possibilités :
- Soit utiliser un contrôle qui dérive de ScrollableControl et positionner la propriété AutoScroll à true
- Soit tout refaire à la main (et oui, le framework ne propose aucune alternative [à ma connaissance]).
Problème : le comportement du ScrollableControl n'est pas toujours celui qu'on veut, pire il peut provoquer différents bugs au niveau de nos applicatifs !
Point 1 : la molette de la souris
Si vous utilisez votre molette sur un contrôle avec la propriété AutoScroll à true, le ScrollableControl va automatiquement scroller son contenu.
C'est exactement ce qu'on veut. Sauf que si vous vous êtes abonné à l'évènement Scroll du ScrollableControl vous pouvez toujours attendre d'être appelé !
Et oui, si vous reflectez le code, vous vous apercevrez que le ScrollableControl modifie effectivement les valeurs de scrolling, mais n'appelle pas l'évènement Scroll.
Voici un bout de code qui permet de contourner le problème :
protected override void OnMouseWheel(MouseEventArgs e) { Point old = this.AutoScrollPosition; base.OnMouseWheel(e); if (old != this.AutoScrollPosition) this.OnScroll(new ScrollEventArgs(ScrollEventType.ThumbPosition, -1)); }
Point 2 : gestion du focus
Lorsqu'un contrôle se trouvant dans un ScrollableControl récupère le focus, le ScrollableControl va automatiquement scroller jusqu'à lui, afin de le mettre en valeur (normal).
Dans le cadre du projet Owandy, nous utilisons le Scroll afin de se déplacer dans une image. Pour des raisons purement applicatives, le contrôle image doit récupérer le focus, le ScrollableControl va donc scroller pour le positionner en haut à gauche.
Problème : à chaque fois que je donne le focus à mon contrôle image, je reviens en haut à gauche ce qui ne me convient pas du tout.
Pour détourner ce comportement, vous devez surcharger une méthode du ScrollableControl :
protected override Point ScrollToControl(System.Windows.Forms.Control activeControl) { return activeControl.Location; }
