WPF MyTextBox.Focus() returns true 但似乎 window 实际上有焦点

WPF MyTextBox.Focus() returns true but it seems the window actually has focus

所以当我的 window 打开时,在 Loaded 事件中,我设置

MyTextBox.Focus();

这很好用,Focus Visual 在那里,插入符号闪烁,我可以打字,没问题。单击 TreeView 中的一个节点,我想修改文本框的文本并重新聚焦文本框,以便用户可以继续键入。我叫:

    MyTextBox.Focus();

再来一次。焦点视觉不会出现在文本框上,并且光标不在文本框中。但是,Keyboard.FocusedElement == MyTextBox 为真。两个奇怪的地方:

A) 我在 window 上有一个按钮 [_Save]。如果我只是按 'S'(没有 Alt- 修饰符),那个按钮就被按下了,就像 window 正在接受我的击键!

B) 如果我在键盘上按 TAB,window 上的第一个控件被 selected,最终,我能够 select 我想要的控件并且它完美运行。

任何地方都没有设置明确的焦点范围。

此外,如果我尝试遍历或 InputManager.Current.ProcessInput(某些选项卡)或其他一些方法来尝试使 window 正确地给予 MyTextBox 焦点 , none 他们工作。

这是一个普通的 WPF 应用程序,没有任何特殊之处styling/templating,我已经无计可施了!

在 TreeView GotFocus 事件中将焦点设置回 TextBox。 示例:

XAML

        <TreeView x:Name="tw" GotFocus="tw_GotFocus">
            <TreeViewItem Header="twh1">
                <TreeViewItem Header="twh2" Selected="TreeViewItem_Selected"></TreeViewItem>
            </TreeViewItem>
        </TreeView>
        <TextBox x:Name="MyTextBox"/>

CS

    private void TreeViewItem_Selected(object sender, RoutedEventArgs e)
    {
        MyTextBox.AppendText(((TreeViewItem)sender).Header.ToString());
        MyTextBox.CaretIndex = MyTextBox.Text.Length;
    }

    private void tw_GotFocus(object sender, RoutedEventArgs e)
    {
        MyTextBox.Focus();
    }

好吧,我过去在使用旧的基于 VSTO 的 WPF 应用程序时遇到过这个问题,我也采用了我想出的解决方案来在这里工作。这是一个扩展方法:

using System.Threading.Tasks;
using System.Windows;

namespace My.Extensions
{
    public static class UiElementExtensions
    {
        /// <summary>
        /// Use when the normal Focus() just refuses to cooperate.
        /// Don't use rapidly in succession unless you rewrite the whole thing to return a Task.
        /// </summary>
        /// <param name="it">The UIElement to give focus.</param>
        /// <param name="delay">Try less than 20 ms at your end users' peril.</param>
        public static void FocusHarder(this UIElement it, int delay = 20)
        {
            var w = new Window { Width = 0, Height = 0, Visibility = Visibility.Hidden };
            w.Loaded += async (_, _) =>
            {
                await Task.Delay(delay);
                it.Focus();
                w.Close();
            };
            w.Show();
        }
    }
}

用它代替.Focus(),如:

MyTextBox.FocusHarder();

我知道这是一个 hack,但如果它不能非常可靠地工作,我会被诅咒的。我不确定 20 毫秒的延迟实际上需要多长时间,但在我的测试中,小于 20 毫秒的延迟有时在某些最终用户的系统上不起作用。

我开始认为这是一个几乎无处不在的 WPF 计时错误。