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

Dab*_*rnl 0 .net wpf focus

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

private void Button_Click(object sender,EventArgs e)
{
  Keyboard.Focus(MyUserControl);
}
Run Code Online (Sandbox Code Playgroud)

没运气.然后我通过TextBox类型的属性在UserControl中公开了Textbox

private void Button_Click(object sender,EventArgs e)
{
  Keyboard.Focus(MyUserControl.TextBox);
}
Run Code Online (Sandbox Code Playgroud)

再没有运气.最后,我在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!
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

Ray*_*rns 6

您可以.Focus()通过使用Dispatcher.BeginInvoke延迟实际Focus()调用来调用,直到ClickMouseDown事件处理程序完成并且调用代码已完成工作.

这是怎么做的:

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);
  });
}
Run Code Online (Sandbox Code Playgroud)

以下是事件序列:

  1. WPF调用MouseDown处理程序
  2. 您的MouseDown处理程序要求WPF Dispatcher在所有DispatcherPriority.Input(和更高版本)调用完成后调用它
  3. 您的MouseDown处理程序返回,调用代码完成其处理
  4. 处理队列中的任何其他输入事件
  5. 您的操作被调用,您的代码调用Keyboard.Focus(FocusedTextBox)以设置焦点.

这里的关键点是KeyboardFocus.Focus()在处理程序返回并且WPF完成所有挂起的输入处理之后才会调用.

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