web-dev-qa-db-fra.com

WPF - Supprimer le focus lorsque vous cliquez en dehors d'une zone de texte

J'ai quelques zones de texte sur lesquelles j'aimerais que le focus se comporte un peu différemment que la normale pour une application WPF. En gros, j'aimerais qu'ils se comportent davantage comme un champ de texte sur une page Web. C'est-à-dire que si je clique n'importe où en dehors de la zone de texte, le focus disparaîtra. Quelle est la meilleure façon de le faire?

Si la solution consiste à supprimer le focus par programme, quel est le meilleur moyen de détecter un clic de souris en dehors des limites? Et si l'élément sur lequel je clique sera le nouveau destinataire de focus?

22
JacobJ

Plutôt que d'ajouter un nouveau contrôle à la fenêtre, je pense que vous devriez donner à votre Grille un nom et réagir à l'événement MouseDown sur votre fenêtre, en déplaçant le focus sur la Grille . Quelque chose comme ça: 

<Window x:Class="WpfApplication1.Window1"
    xmlns="http://schemas.Microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.Microsoft.com/winfx/2006/xaml" 
    Title="Window1" Height="412" Width="569" MouseDown="Window_MouseDown" Name="window1" >
    <Grid ShowGridLines="False" KeyDown="Grid_KeyDown" Name="grid1" Focusable="True">
          <TextBox HorizontalAlignment="Left" Margin="117,61,0,0" Name="textBox1" VerticalAlignment="Top" Width="120" />
    </Grid>
</Window>

code derrière:

private void window1_MouseDown(object sender, MouseButtonEventArgs e)
{
    grid1.Focus();
}
26

Je pense que la meilleure façon de résoudre ce problème consiste à ajouter le gestionnaire d’événements MouseDown à la fenêtre avec le code derrière:

private void window_MouseDown(object sender, MouseButtonEventArgs e)
{
    Keyboard.ClearFocus();
}
12
NightEagle

Une autre façon qui a fonctionné pour moi utilisait

Mouse.AddPreviewMouseDownOutsideCapturedElementHandler

Par exemple, supposons que vous ayez un TextBlock qui, une fois cliqué, devienne éditable en affichant une TextBox ciblée. Ensuite, lorsque l'utilisateur clique en dehors de la zone de texte, celle-ci doit être masquée à nouveau. Voici comment vous pouvez le faire:

private void YourTextBlock_OnMouseDown(object sender, MouseButtonEventArgs e)
{
    YourTextBox.Visibility = Visibility.Visible;
    YourTextBox.Focus();
    CaptureMouse();
    Mouse.AddPreviewMouseDownOutsideCapturedElementHandler(this, OnMouseDownOutsideElement);
}

private void OnMouseDownOutsideElement(object sender, MouseButtonEventArgs e)
{
    Mouse.RemovePreviewMouseDownOutsideCapturedElementHandler(this, OnMouseDownOutsideElement);
    ReleaseMouseCapture();
    YourTextBox.Visibility = Visibility.Hidden;
}
3
Mr. Bungle

Je ne suis pas sûr à 100%, mais si vous définissez Focusable sur true sur l'élément conteneur (Grid, StackPanel, etc.), le focus devrait être retiré de la zone de texte.

2
Richard Szalay

Si vous avez cliqué sur l'élément qui peut capturer le focus, vous obtenez ce dont vous avez besoin. Si, par exemple, vous avez un panneau, vous pouvez gérer l'événement mouseClick pour répondre à vos besoins ou utiliser les conseils de Richard Szalay.

1
stukselbax

Pour éviter le code en retard, vous pouvez utiliser ce comportement Le comportement

 public class ClearFocusOnClickBehavior : Behavior<FrameworkElement>
 {
    protected override void OnAttached()
    {
        AssociatedObject.MouseDown += AssociatedObject_MouseDown;
        base.OnAttached();
    }

    private static void AssociatedObject_MouseDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
    {
        Keyboard.ClearFocus();
    }

    protected override void OnDetaching()
    {
        AssociatedObject.MouseDown -= AssociatedObject_MouseDown;
    }
}

Utilisation en XAML:

Sur tout élément en dehors de la zone de texte sur lequel vous voulez qu'il efface le focus, cliquez sur Ajouter:

    <i:Interaction.Behaviors>
        <behaviors:ClearFocusOnClickBehavior/>
    </i:Interaction.Behaviors>
1
shmoltz

J'ai essayé la réponse sélectionnée dans l'application native WPF de réaction, mais cela ne provoquait pas la perte de la focalisation de la zone de texte en raison de la zone de texte qui ne perdait pas la focalisation. La solution suivante fonctionne pour moi.

Lier un événement de souris vers le bas à la fenêtre:

<Window x:Class="WpfApplication1.Window1"
    xmlns="http://schemas.Microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.Microsoft.com/winfx/2006/xaml" 
    Title="Window1" Height="412" Width="569" MouseDown="window_MouseDown" Name="window1" >
    <Grid ShowGridLines="False" KeyDown="Grid_KeyDown" Name="grid1" Focusable="True">
          <TextBox HorizontalAlignment="Left" Margin="117,61,0,0" Name="textBox1" VerticalAlignment="Top" Width="120" />
    </Grid>
</Window>

et l'événement est:

private void window_MouseDown(object sender, MouseButtonEventArgs e)
{
    TextBox textBox = Keyboard.FocusedElement as TextBox;
    if (textBox != null)
    {
        TraversalRequest tRequest = new TraversalRequest(FocusNavigationDirection.Next);
        textBox.MoveFocus(tRequest);
    }
}
0
Zaheer Ahmed

Vous pouvez utiliser l'événement IsKeyboardFocusedChanged:

myTextBox.IsKeyboardFocusedChanged += myTextBox_IsKeyboardFocusedChanged;

private void SendFileCaptionTextBox_IsKeyboardFocusedChanged(object sender, DependencyPropertyChangedEventArgs e)
{
    if (e.NewValue.ToString() == "True")
    {
        // it's focused
    }
    else
    {
        // it's not focused
    }
}    
0
Mayer Spitzer

vous ne pouvez pas explicitement perdre le focus d'un contrôle

vous pouvez définir le focus sur un autre contrôle à la place

**txt.Focusable=true;
label.focus();
Keyboard.Focus(txtPassword);**

essaye ça

0
user3060599

Je rencontrais un problème similaire, mais lorsque j’enveloppais mes champs de texte autour d’un contrôle ScrollViewer, tous les champs de texte perdaient automatiquement le focus lorsque vous cliquez à l’extérieur des texboxes.

0
Kristofer Escobar