Reputation: 1704
I have an application in WPF that is to be used exclusively by the keyboard, so we are really picky about focus behavior.
So, we get a PreviewLostKeyboardFocus on a textbox. Under certain circumstances we disable the next 5 fields and want the focus to go to the field after that. One might assume that the focus would do that, finding the next focusable field, this is what happens if I didn't disable the fields in the preview event. It doesn't, it keeps the focus on the first textbox.
I've tried forcing the focus with Keyboard.Focus(uielement)
but nothing happens. It seems that the next focus target is already commited.
How can I make this happen, or am I "doing it wrong"? I am not in a position to change the requirement that specifies this behavior; I know that it is somewhat strange.
Thanks.
Edit: here is a small app that shows this behavior. XAML:
<Window x:Class="WpfApplication4.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525"
FocusManager.FocusedElement="{Binding ElementName=textBox0}"
>
<StackPanel>
<TextBox Height="23" Margin="5" Name="textBox0" Width="120" />
<TextBox Height="23" Margin="5" Name="textBox1" Width="120" PreviewLostKeyboardFocus="textBox1_PreviewLostKeyboardFocus"/>
<TextBox Height="23" Margin="5" Name="textBox2" Width="120" />
<TextBox Height="23" Margin="5" Name="textBox3" Width="120" />
<TextBox Height="23" Margin="5" Name="textBox4" Width="120" />
</StackPanel>
</Window>
Codebehind:
using System.Windows;
using System.Windows.Input;
namespace WpfApplication4 {
public partial class MainWindow : Window {
public MainWindow() {
InitializeComponent();
}
private void textBox1_PreviewLostKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e) {
textBox2.IsEnabled = false;
textBox3.IsEnabled = false;
}
}
}
An obvious thing to try (at least for me) was to put Keyboard.focus(textBox4);
in the PreviewLostKeyboardFocus
event handler. It of course didn't work, it causes a loop that fires the PreviewLostKeyboardFocus
event again....
Yet another edit:
I've found that using breakpoints in textBox1_PreviewLostKeyboardFocus()
will sometimes cause it to behave, or sometimes not even disable the 2nd and 3rd text boxes. I'm thinking of a race/threading problem.
Upvotes: 4
Views: 1427
Reputation: 14411
I am not sure what exactly is causing this behavior but from past experience the WPF focus system is extremely unreliable after changing the controls in any way or when setting focus manually.
However, using a Dispatcher to perform focus changes after WPF caught up with the changes to the controls, often solves the problem.
This works fine in my testing
private void textBox1_PreviewLostKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e) {
textBox2.IsEnabled = false;
textBox3.IsEnabled = false;
this.Dispatcher
.BeginInvoke(new Action(() => Keyboard.Focus(textBox4)),
System.Windows.Threading.DispatcherPriority.Input, null);
}
Upvotes: 3
Reputation: 4383
You might be able to do this better via the viewmodel. Your view model could set bool properties to enable/disable fields. I"m sure you'd rather not flood a viewmodel like that, but it may make the app behavior more predicable. I think wpf knows to skip tabstops on disabled controls, and you may be able to find a desired tab behavior in the tab navigation.
Upvotes: 0