WPF - убрать фокус при нажатии за пределами текстового поля - PullRequest
23 голосов
/ 27 июня 2011

У меня есть несколько текстовых полей, в которых я хотел бы, чтобы фокус работал немного иначе, чем обычно для приложения WPF.По сути, я бы хотел, чтобы они вели себя как текстовое поле на веб-странице.То есть, если я щелкну где-нибудь за пределами текстового поля, оно потеряет фокус.Каков наилучший способ сделать это?

Если ответ заключается в программном удалении фокуса, каков наилучший способ обнаружения щелчка мышью за пределами границ?Что, если элемент, на который я нажимаю, будет новым получателем фокуса?

Ответы [ 11 ]

26 голосов
/ 27 июня 2011

Вместо того, чтобы добавлять новый элемент управления в окно, я думаю, что вы должны дать вашему Grid имя и реагировать на событие MouseDown в вашем окне, перемещая фокус на Сетка сама.Примерно так:

<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>

код позади:

private void window1_MouseDown(object sender, MouseButtonEventArgs e)
{
    grid1.Focus();
}
13 голосов
/ 06 января 2014

Я думаю, что лучший способ решить эту проблему - добавить обработчик событий MouseDown в окно с кодом позади:

private void window_MouseDown(object sender, MouseButtonEventArgs e)
{
    Keyboard.ClearFocus();
}
3 голосов
/ 28 июня 2018

Чтобы избежать кода позади, вы можете использовать это поведение Поведение

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

Использование в XAML:

На любом элементе за пределами текстового поля, который вы хотите, чтобы он очистил фокус при нажатии Добавить:

    <i:Interaction.Behaviors>
        <behaviors:ClearFocusOnClickBehavior/>
    </i:Interaction.Behaviors>
3 голосов
/ 16 апреля 2016

Еще один способ, который работал для меня, это использование

Mouse.AddPreviewMouseDownOutsideCapturedElementHandler

Например, скажем, у вас есть TextBlock, который при нажатии должен стать редактируемым, показывая сфокусированный TextBox. Затем, когда пользователь щелкнул за пределами TextBox, он должен быть снова скрыт. Вот как вы можете это сделать:

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;
}
2 голосов
/ 27 июня 2011

Я не уверен на 100%, но если вы установите для Focusable значение true для элемента контейнера (Grid, StackPanel и т. Д.), То это должно отвлечь фокус от текстового поля.

1 голос
/ 19 июня 2017

У меня была похожая проблема, но когда я обернул элемент управления ScrollViewer вокруг своих текстовых полей, все текстовые поля автоматически теряли фокус при щелчке в любом месте за пределами текстовых полей.

1 голос
/ 27 июня 2011

Если вы нажали на элемент, который может захватить фокус, вы получите то, что вам нужно.если, например, у вас есть какая-то панель, вы можете обработать событие mouseClick панели, чтобы удовлетворить ваши потребности, или воспользоваться советом Ричарда Сзалая.

0 голосов
/ 05 апреля 2019
public class ClearFocusOnOutsideClickBehavior : Behavior<FrameworkElement>
{
    protected override void OnAttached()
    {

        AssociatedObject.GotFocus += AssociatedObjectOnGotFocus;
        AssociatedObject.LostFocus += AssociatedObjectOnLostFocus;
        base.OnAttached();
    }

    private void AssociatedObjectOnLostFocus(object sender, RoutedEventArgs e)
    {
        App.Current.MainWindow.MouseUp -= _paren_PreviewMouseUp;
    }

    private void AssociatedObjectOnGotFocus(object sender, RoutedEventArgs e)
    {
        App.Current.MainWindow.MouseUp += _paren_PreviewMouseUp;
    }

    private void _paren_PreviewMouseUp(object sender, MouseButtonEventArgs e)
    {
        Keyboard.ClearFocus();
    }

    protected override void OnDetaching()
    {
        AssociatedObject.GotFocus -= AssociatedObjectOnGotFocus;
        AssociatedObject.LostFocus -= AssociatedObjectOnLostFocus;
    }
}

Использование в XAML:

<TextBox Height="30" Width="200">
            <i:Interaction.Behaviors>
                <behaviours:ClearFocusOnOutsideClickBehavior/>
            </i:Interaction.Behaviors>
 </TextBox>
0 голосов
/ 04 октября 2018

Я пробовал выбранный ответ в приложении WPF реагировать, но он не вызывал потерю фокуса текстового поля, из-за которого текстовое поле не теряло фокус.Следующее решение работает для меня.

Привязать событие мыши к окну:

<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>

, а событие:

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 голосов
/ 18 января 2018

Вы можете использовать событие 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
    }
}    
...