Расфокусировка элементов WPF. Как убрать фокус?
Имеется страничка WPF с различными элементами, такими как: TextBox, PasswordBox, ListView.
Если фокус был на TextBox, и я кликну на PasswordBox — фокус будет передан последнему, но я не смогу снять фокус вообще.
Вариант с прописанием Grid/Window или другому "контейнеру" функции KeyDown не дал никаких результатов.
Как создать функцию, которая при клике вне области любого из элементов очистит фокус?
Дополнено:
В стиле для TextBox и PasswordBox я прописал следующие триггеры:
<Style.Triggers>
<Trigger Property="IsFocused" Value="True">
<Setter Property="BorderBrush" Value="#f3ca40"/>
</Trigger>
<Trigger Property="IsFocused" Value="False">
<Setter Property="BorderBrush" Value="Transparent"/>
</Trigger>
</Style.Triggers>
Так вот, возможность редактировать текст внутри элемента пропадает, когда использую любой из методов @EvgeniyZ, фокус вроде бы снят, однако, почему-то не меняется цвет у Border'а на "Transparent".
Ответы (1 шт):
В WPF есть такая вещь, как Keyboard.ClearFocus();, она сбрасывает фокус с элементов при вызове.
Имея такой метод, мы можем его вызывает, например при клике мыши по самому окну, где клик будем отлавливать событием MouseDown, что в итоге даст нам такое:
<Window ... MouseDown="Window_MouseDown" >
<StackPanel>
<TextBox/>
<PasswordBox/>
</StackPanel>
</Window>
и C#
public partial class MainWindow : Window
{
public MainWindow() => InitializeComponent();
private void Window_MouseDown(object sender, MouseButtonEventArgs e) => Keyboard.ClearFocus();
}
Видим, что фокус успешно сбрасывается при клике за пределы элементов.
Мы можем пойти дальше и сделать на основе этого, к примеру свой класс поведения (Behavior):
Подключаем System.Windows.Interactivity.WPF или лишь Microsoft.Xaml.Behaviors
Создаем новый класс с нужным нам названием и пишем в нем примерно следующее:
class ClearFocusBehavior : Behavior<FrameworkElement> { protected override void OnAttached() => AssociatedObject.MouseDown += AssociatedObject_MouseDown; private void AssociatedObject_MouseDown(object sender, MouseButtonEventArgs e) => Keyboard.ClearFocus(); protected override void OnDetaching() => AssociatedObject.MouseDown -= AssociatedObject_MouseDown; }В XAML, к нужному объекту добавляем наше новое поведение, я, например перепишу код выше:
<Window ... xmlns:i="http://schemas.microsoft.com/xaml/behaviors"> <i:Interaction.Behaviors> <local:ClearFocusBehavior/> </i:Interaction.Behaviors> <StackPanel> <TextBox/> <PasswordBox/> </StackPanel> </Window>
Результатом будет аналогичное поведение, что и выше.
Альтернативным путем решения может послужить метод .Focus(); у нужного компонента, например на основном Grid (<Grid x:Name="mainGrid"> и mainGrid.Focus();).
а можно ли как-то логический фокус убрать?
За него отвечает FocusManager, при помощи которого мы можем задать фокус нужному объекту (.SetFocusedElement()), а если ему задать объект, null, то он должен этот фокус убрать. Как я понял, без разницы какой объект, я эксперементировал с тем же главным окном и все успешно сбросило. Так что, если вам именно такой вариант нужен, то:
Вариант через событие и его
sender:private void Window_MouseDown(object sender, MouseButtonEventArgs e) { if(sender is FrameworkElement element) { FocusManager.SetFocusedElement(FocusManager.GetFocusScope(element), null); Keyboard.ClearFocus(); } }Behavior:private void AssociatedObject_MouseDown(object sender, MouseButtonEventArgs e) { FocusManager.SetFocusedElement(FocusManager.GetFocusScope(AssociatedObject), null); Keyboard.ClearFocus(); }
Если будут проблемы, то как я сказал выше, ищите выделенный объект, а не как здесь объект, к которому было добавлено поведение и который вызывает событие.
