Comment un contrôle peut-il gérer un clic de souris en dehors de ce contrôle?

J’écris un contrôle personnalisé et j’aimerais que le contrôle passe d’un état d’édition à son état normal lorsqu’un utilisateur quitte le contrôle. Je gère l’événement LostFocus, ce qui est utile lorsque l’utilisateur clique ou s’il clique sur un autre contrôle Focusable. Mais s’ils ne cliquent pas sur quelque chose de Focusable, il ne sortira pas de son état d’édition. J’ai donc deux solutions en tête:

  • Parcourez l’arborescence jusqu’au premier élément lorsqu’il passe à un état d’édition et ajoutez un gestionnaire pour MouseDownEvent (et gérez les événements “traités”). Dans le gestionnaire, jetterais le contrôle hors de son état d’édition et supprimerait le gestionnaire de l’élément le plus en haut. Cela semble être un peu un bidouillage, mais cela fonctionnerait probablement bien.

Exemple de code:

 private void RegisterTopMostParentMouseClickEvent() { _topMostParent = this.FindLastVisualAncestor(); if ( _topMostParent == null ) return; _topMostParent.AddHandler( Mouse.MouseDownEvent, new MouseButtonEventHandler( CustomControlMouseDownEvent ), true ); } private void UnRegisterTopMostParentMouseClickEvent() { if ( _topMostParent == null ) return; _topMostParent.RemoveHandler( Mouse.MouseDownEvent, new MouseButtonEventHandler( CustomControlMouseDownEvent ) ); _topMostParent = null; } 
  • Utilisez Mouse.PreviewMouseDownOutsideCapturedElement et ajoutez un gestionnaire à mon contrôle. Dans le gestionnaire, je mettrais le contrôle hors de son état d’édition. Mais je ne semble pas avoir l’événement à tirer. Quand est-ce que l’object Mouse.PreviewMouseDownOutsideCapturedElement est lancé?

Exemple de code:

 AddHandler( Mouse.PreviewMouseDownOutsideCapturedElementEvent, new MouseButtonEventHandler( EditableTextBlockPreviewMouseDownOutsideCapturedElementEvent ), true ); 

Capturez la souris. Lorsqu’un object capture la souris, tous les événements liés à la souris sont traités comme si l’object avec la capture de la souris exécutait l’événement, même si le pointeur de la souris était au-dessus d’un autre object.

Juste pour clarifier la réponse fournie à propos de la focalisation de la souris – c’était utile, mais je devais approfondir la recherche pour obtenir quelque chose qui fonctionne réellement:

J’essayais de mettre en œuvre quelque chose comme une liste déroulante et j’avais besoin d’un comportement similaire – pour faire disparaître la liste déroulante lorsque vous cliquez sur quelque chose d’autre, sans que le contrôle ait connaissance de ce qui était autre chose.

J’ai eu l’événement suivant pour un bouton déroulant:

  private void ClickButton(object sender, RoutedEventArgs routedEventArgs) { //do stuff (eg activate drop down) Mouse.Capture(this, CaptureMode.SubTree); AddHandler(); } 

CaptureMode.SubTree signifie que vous n’obtenez que les événements extérieurs au contrôle et que toute activité de la souris dans le contrôle est transmise normalement. Vous n’avez pas l’option de fournir cet enum dans CaptureMouse de UIElement, cela signifie que vous obtiendrez des appels à HandleClickOutsideOfControl INSTEAD des appels vers les contrôles enfants ou autres gestionnaires du contrôle. C’est le cas même si vous ne vous abonnez pas aux événements qu’ils utilisent – la capture complète de la souris est un peu trop!

  private void AddHandler() { AddHandler(Mouse.PreviewMouseDownOutsideCapturedElementEvent, new MouseButtonEventHandler(HandleClickOutsideOfControl), true); } 

Vous devez également vous accrocher pour supprimer le gestionnaire aux endroits appropriés, mais je l’ai laissé ici par souci de clarté et de concision.

Enfin, dans le gestionnaire, vous devez libérer la capture à nouveau.

  private void HandleClickOutsideOfControl(object sender, MouseButtonEventArgs e) { //do stuff (eg close drop down) ReleaseMouseCapture(); } 

J’obtiens généralement la fenêtre parente et ajoute un gestionnaire de prévisualisation, même s’il est déjà géré. Parfois, lorsque MouseCapture ne suffit pas, cette technique est pratique:

 Window.GetWindow(this).AddHandler ( UIElement.MouseDownEvent, (MouseButtonEventHandler)TextBox_PreviewMouseDown, true ); 

J’aborderais ceci d’une manière différente – le formulaire qui contient le contrôle supprime le focus du contrôle lorsqu’un utilisateur clique sur une autre partie du formulaire.

Avoir le contrôle réellement flou est bien plus simple que d’essayer de perdre le contrôle «simulé» dans certaines situations, alors que ce n’est pas le cas. Gardez à l’esprit que si le contrôle n’a pas vraiment perdu le focus, il acceptera tout de même des choses comme la saisie au clavier.