如何以编程方式将键盘焦点设置为用户控件内的文本框?

时间:2009-11-18 10:05:20

标签: .net wpf focus

我有一个包含文本框的UserControl。我想在用户单击按钮时以编程方式将keyboardfocus设置为此文本框。 我试过这个:

private void Button_Click(object sender,EventArgs e)
{
  Keyboard.Focus(MyUserControl);
}
没有运气。然后我通过TextBox

类型的属性在UserControl中公开了Textbox
private void Button_Click(object sender,EventArgs e)
{
  Keyboard.Focus(MyUserControl.TextBox);
}
再一次没有运气。最后,我在UserControl中创建了一个eventhandler来处理GotKeyboardFocus事件,在其中的文本框上调用Keyboard.Focus方法。

再次没有运气?!

怎么做?

编辑: 该问题与UserControls无关。当您尝试将焦点传递给Click或MouseDownHandler中的其他UIElement时,这是一个问题。 下面的XAML代码讲述了他们自己的故事:焦点确实传递到文本框但被列表框偷走了。

<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_MouseDown(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!
        }
    }
}

2 个答案:

答案 0 :(得分:6)

您可以使用.Focus()延迟实际的Dispatcher.BeginInvoke来电,直到Focus()Click事件处理程序完成并{调用代码已完成工作。

以下是如何操作:

MouseDown

以下是事件序列:

  1. WPF调用您的MouseDown处理程序
  2. 您的MouseDown处理程序要求WPF Dispatcher在所有DispatcherPriority.Input(及更高版本)调用完成后调用它
  3. 您的MouseDown处理程序返回,调用代码完成其处理
  4. 处理队列中的任何其他输入事件
  5. 您的操作已被调用,您的代码会调用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); }); } 来设置焦点。
  6. 这里的关键点是,在您的处理程序返回并且WPF完成所有待处理的输入处理之后才会调用 Keyboard.Focus(FocusedTextBox)

    KeyboardFocus.Focus()调用本身可能会触发ListBox从您那里窃取焦点。我没有检查过这个。如果是这种情况,解决方案是调用它两次:一次来自MouseDown处理程序,再次来自MouseDown处理程序调度的Action。因此,如果它对注释掉的第一行不起作用,请取消注释并重试。

答案 1 :(得分:3)

MyUserControl.FindControl("TextBox1").Focus();

失败了......

(TextBox)(MyUserControl.FindControl("TextBox1")).Focus();