WPF: Comment supprimer par programme le focus d'un TextBox

96

Je veux ajouter un comportement simple (du moins je pensais que c'était) à mon WPF TextBox.

Lorsque l'utilisateur appuie sur Echap, je veux TextBoxque le texte qu'il édite ait le texte qu'il avait lorsque l'utilisateur a commencé à modifier, ET je veux supprimer le focus du TextBox.

Je n'ai aucun problème à définir le texte pour la valeur qu'il avait au début de l'édition.

Le problème est de supprimer le focus de l'élément. Je ne veux pas déplacer le focus vers un autre composant, je veux juste le TextBoxperdre. Dois-je avoir un élément invisible pour définir le focus afin que je TextBoxpuisse perdre le focus?

jpsstavares
la source

Réponses:

152

dans .NET Framework 4 uniquement Keyboard.ClearFocus();

LPL
la source
1
C'était exactement ce que je cherchais ce soir!
Josh
9
Cela ne clarifie pas toujours le focus: j'ai un problème où un AutoCompleteTextBox à l'intérieur d'un ListBox ne perd pas le focus lorsque je cours à Keyboard.ClearFocus()partir de code-behind après un clic quelque part.
ANeves pense que SE est diabolique
3
ClearFocusfait GotFocusde ne pas se déclencher pour le contrôle récemment focalisé alors qu'il se déclenche toujours pour d'autres contrôles. C'est un gros problème pour mon clavier à l'écran personnalisé, par exemple. Cela fait disparaître le signe d'insertion, ce qui est probablement tout ce que le "focus clavier" implique. Peut-être que je suis plus intéressé par quelque chose comme "focus souris".
Grault
2
Merci Grault, j'ai le même problème. Le mieux que j'ai trouvé est de déplacer le focus vers un autre contrôle other.Focus().
Tor Klingberg
7
@Grault Ceci efface uniquement le focus clavier, pas le focus logique (qui est ce qui déclenche l' GotFocusévénement). Il y a toujours quelque chose avec une orientation logique dans votre programme. Utilisez l' LostKeyboardFocusévénement ou déplacez le focus vers un autre élément (qui déplace le focus logique avec lui) avant de supprimer le focus clavier.
Chirimorin
54

Le code que j'utilise:

// Move to a parent that can take focus
FrameworkElement parent = (FrameworkElement)textBox.Parent;
while (parent != null && parent is IInputElement && !((IInputElement)parent).Focusable)
{
    parent = (FrameworkElement)parent.Parent;
}

DependencyObject scope = FocusManager.GetFocusScope(textBox);
FocusManager.SetFocusedElement(scope, parent as IInputElement);
Decasteljau
la source
2
Ce code est génial, Keyboard.ClearFocus () a des effets secondaires involontaires
patrick
Pourquoi la condition! ((IInputElement) parent) .Focusable a "!" devant? Cette condition ne devrait-elle pas être vraie si le parent est focalisable?
Mert Akcakaya
Mert - pas sûr, mais en parcourant simplement cet article, il semble que continuer à boucler jusqu'à ce que cette condition soit vraie est le point. De cette façon, le premier élément focalisable termine la boucle.
jpierson
4
@patrick, quels effets secondaires involontaires? Pouvez-vous donner des exemples pertinents?
ANeves pense que SE est mal le
1
C'est une excellente solution. J'ai également eu des problèmes avec Keyboard.ClearFocus (). Lors de l'exécution de ClearFocus () sur une zone de texte à l'intérieur d'une fenêtre modale, la zone de texte et la fenêtre perdent le focus. Cela signifie que les événements KeyDown ne vont plus dans la fenêtre. En le modifiant à la place pour que le Focus se transforme en parent (qui peut être la fenêtre), les futurs événements KeyDown ne sont pas perdus. Dans mon exemple pratique, j'ai la fenêtre à la recherche de "Key.Escape" et en appelant Close (). Cela cesse de fonctionner si vous exécutez ClearFocus () n'importe où.
Denis P
19

Un peu tard à la fête, mais cela m'a été utile alors voilà.

Depuis .Net 3.0, FrameworkElementa une fonction MoveFocus qui a fait l'affaire pour moi.

SuperOli
la source
Pour obtenir des instructions -> msdn.microsoft.com/en-us/library/…
Carter Medlin
"Assurez-vous de vérifier la valeur de retour de cette méthode. Une valeur de retour de false peut être retournée si le parcours s'exécute dans un taquet de tabulation défini par la composition d'un contrôle et que la demande de parcours n'a pas demandé de retour à la ligne." - msdn.microsoft.com/en-us/library/…
aderesh
13

Étant donné qu'aucune des réponses ci-dessus n'a fonctionné pour moi et que la réponse acceptée ne fonctionne que pour un focus clavier, je suis arrivé à l'approche suivante:

// Kill logical focus
FocusManager.SetFocusedElement(FocusManager.GetFocusScope(textBox), null);
// Kill keyboard focus
Keyboard.ClearFocus();

Tue les deux, logique ainsi que le focus clavier.

Cyclone
la source
9

Vous pouvez définir le focus sur un ancêtre focalisable. Ce code fonctionnera même si la zone de texte se trouve dans un modèle sans ancêtres focalisables à l'intérieur de ce même modèle:

DependencyObject ancestor = textbox.Parent;
while (ancestor != null)
{
    var element = ancestor as UIElement;
    if (element != null && element.Focusable)
    {
        element.Focus();
        break;
    }

    ancestor = VisualTreeHelper.GetParent(ancestor);
}
Julian Dominguez
la source
6

AFAIK, il n'est pas possible de supprimer complètement la mise au point. Quelque chose dans votre fenêtre aura toujours le focus.

bitbonk
la source
2

Dans le développement de Windows Phone, je viens de le faire Focus()ou this.Focus()dans la PhoneApplicationPage et cela a fonctionné comme un charme.

Bruno Lemos
la source
1

Pour moi, c'est assez délicat, en particulier lors de l'utilisation avec la liaison LostFocus. Cependant, ma solution de contournement consiste à ajouter une étiquette vide et à me concentrer dessus.

<Label Name="ResetFocusArea" Focusable="True" FocusVisualStyle="{x:Null}" />

...

OnKeyDown(object sender, RoutedEventArgs e)
{
  //if is Esc
  ResetFocusArea.Focus();
}
Brian Ng
la source
0

Ma réponse ne répond pas directement à la question ci-dessus, cependant, je pense que le libellé de celui-ci l'a amenée à devenir "La question" sur la suppression programmatique de la concentration. Un scénario courant où cela est nécessaire est que l'utilisateur puisse effacer le focus en cliquant avec le bouton gauche sur l'arrière-plan d'un contrôle racine, comme une fenêtre.

Donc, pour y parvenir, vous pouvez créer un comportement attaché qui basculera le focus vers un contrôle créé dynamiquement (dans mon cas, une étiquette vide). Il est préférable d'utiliser ce comportement sur les éléments de plus haut niveau comme les fenêtres, car il parcourt ses enfants pour trouver un panneau auquel il peut ajouter une étiquette factice.

public class LoseFocusOnLeftClick : Behavior<FrameworkElement>
{
    private readonly MouseBinding _leftClick;
    private readonly Label _emptyControl = new Label() { Focusable = true, HorizontalAlignment = HorizontalAlignment.Left, VerticalAlignment = VerticalAlignment.Top };

    public LoseFocusOnLeftClick()
    {
        _leftClick = new MouseBinding(new RelayCommand(LoseFocus), new MouseGesture(MouseAction.LeftClick));
    }

    protected override void OnAttached()
    {
        AssociatedObject.InputBindings.Add(_leftClick);
        AssociatedObject.Loaded += AssociatedObject_Loaded;
    }        

    protected override void OnDetaching()
    {
        AssociatedObject.InputBindings.Remove(_leftClick);
        AssociatedObject.Loaded -= AssociatedObject_Loaded;
    }

    private void AssociatedObject_Loaded(object sender, RoutedEventArgs e)
    {
        AssociatedObject.Loaded -= AssociatedObject_Loaded;

        AttachEmptyControl();
    }

    private void AttachEmptyControl()
    {            
        DependencyObject currentElement = AssociatedObject;
        while (!(currentElement is Panel))
        {
            currentElement = VisualTreeHelper.GetChild(currentElement, 0);
        }

        ((Panel)currentElement).Children.Add(_emptyControl);
    }

    private void LoseFocus()
    {            
        _emptyControl.Focus();
    }
}
TripleAccrétion
la source