How to set the keyboardfocus to a textbox inside a UserControl programmatically?
I have a UserControl that incorporates a textbox. I want to set the keyboardfocus to this textbox programmatically when the user clicks a button. I tried this:
private void Button_Click(object sender,EventArgs e)
{
Keyboard.Focus(MyUserControl);
}
no luck. Then I exposed the Textbox in the UserControl though a property of type TextBox
private void Button_Click(object sender,EventArgs e)
{
Keyboard.Focus(MyUserControl.TextBox);
}
again no luck. Finally I made an eventhandler in the UserControl to handle the GotKeyboardFocus event, calling the Keyboard.Focus method on the textbox inside it.
Again no luck?!
How to do this??
EDIT: The problem is not related to UserControls. It is an issue when you try to pass focus to an other UIElement in a Click or MouseDownHandler. The XAML en code behind below tell their own story: the focus does pass to the textbox but is stolen back by the listbox.
<Window x:Class="FocusSpike.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="300" Width="300">
<StackPanel>
<TextBox Name="FocusedTextBox" Height="30">
<TextBox.Style>
<Style TargetType="TextBox">
<Setter Property="Text" Value="I am unfocused..."/>
<Setter Property="Opacity" Value=".3"/>
<Style.Triggers>
<Trigger Property="IsKeyboardFocused" Value="True">
<Trigger.EnterActions>
<BeginStoryboard>
<Storyboard AutoReverse="True">
<DoubleAnimation Storyboard.TargetProperty="FontSize" To="20"/>
</Storyboard>
</BeginStoryboard>
</Trigger.EnterActions>
<Setter Property="Text" Value="I am focused!"/>
<Setter Property="Opacity" Value="1"/>
</Trigger>
</Style.Triggers>
</Style>
</TextBox.Style>
</TextBox>
<Button>Click to steal focus.</Button>
<ListBox>
<ListBoxItem GotFocus="Listbox_GotFocus">
<Label MouseDown="ListBoxItem_MouseDown">
Click to restore focus
</Label>
</ListBoxItem>
</ListBox>
</StackPanel>
</Window>
using System.Windows;
using System.Windows.Input;
namespace FocusSpike
{
public partial class Window1 : Window
{
public Window1()
{
InitializeComponent();
FocusedTextBox.Focus();
}
private void ListBoxItem_MouseD开发者_StackOverflowown(object sender, MouseButtonEventArgs e)
{
Keyboard.Focus(FocusedTextBox);//This does not work, remove it!
}
private void Listbox_GotFocus(object sender, RoutedEventArgs e)
{
//Keyboard.Focus(FocusedTextBox);//uncomment to restore focus!
}
}
}
You can get your .Focus()
call to stick by using Dispatcher.BeginInvoke
to delay the actual Focus()
call until the Click
or MouseDown
event handler has completed and the calling code has finished working.
Here is how to do it:
private void ListBoxItem_MouseDown(object sender, MouseButtonEventArgs e)
{
//Keyboard.Focus(FocusedTextBox); // May be necessary to uncomment this in some scenarios
Dispatcher.BeginInvoke(DispatcherPriority.Input, new Action(() =>
{
Keyboard.Focus(FocusedTextBox);
});
}
Here is the sequence of events:
- WPF calls your MouseDown handler
- Your MouseDown handler asks the WPF Dispatcher to call it back when all DispatcherPriority.Input (and higher) invocations have been completed
- Your MouseDown handler returns and the calling code completes its processing
- Any other input events in the queue are processed
- Your Action is called, and your code calls
Keyboard.Focus(FocusedTextBox)
to set the focus.
The key point here is that KeyboardFocus.Focus()
is not called until after your handler has returned and WPF has completed all pending input processing.
It is possible that the KeyboardFocus.Focus()
call itself may trigger ListBox to steal focus from you. I haven't checked this. If that is the case, the solution would be to call it twice: Once from the MouseDown handler and again from the Action scheduled by the MouseDown handler. So if it doesn't work with the first line commented out, uncomment it and try again.
MyUserControl.FindControl("TextBox1").Focus();
Failing that...
(TextBox)(MyUserControl.FindControl("TextBox1")).Focus();
精彩评论