C# 为什么WPF IsKeyboardFocused提供虚假信息?

C# 为什么WPF IsKeyboardFocused提供虚假信息?,c#,wpf,C#,Wpf,我试图遵循回答这个问题时描述的模式。 然而,我在键盘焦点的概念上遇到了麻烦。如果我的记事本或其他应用程序与我的WPF应用程序同时运行,并单击记事本将键盘焦点放在那里,然后采取措施使其他应用程序将焦点放在其中一个文本框中,则触发器会给出视觉提示,表明我的应用程序的文本框现在具有键盘焦点。然而,当我开始打字时,我发现情况并非如此,因为文本实际上进入了记事本 这是我的触发器的xaml <TextBox.Style> <Style TargetType="{x:Type Te

我试图遵循回答这个问题时描述的模式。

然而,我在键盘焦点的概念上遇到了麻烦。如果我的记事本或其他应用程序与我的WPF应用程序同时运行,并单击记事本将键盘焦点放在那里,然后采取措施使其他应用程序将焦点放在其中一个文本框中,则触发器会给出视觉提示,表明我的应用程序的文本框现在具有键盘焦点。然而,当我开始打字时,我发现情况并非如此,因为文本实际上进入了记事本

这是我的触发器的xaml

<TextBox.Style>
    <Style TargetType="{x:Type TextBox}">
        <Style.Triggers>
            <DataTrigger Binding="{Binding ReadyForDataEntry}" Value="True">
                <Setter Property="FocusManager.FocusedElement" Value="{Binding RelativeSource={RelativeSource Self}}" />
           </DataTrigger>
            <Trigger Property="IsKeyboardFocused" Value="true">
                <Setter Property="Background" Value="Lavender"/>
                <Setter Property="BorderBrush" Value="Blue"/>
            </Trigger>
        </Style.Triggers>
 </Style>


本质上,文本框有时会亮起,边框和背景色指示该文本框的IsKeyboardFocused=true,即使最后单击的任何应用程序(例如,一个便笺、记事本)都会收到键盘输入。我错过了什么?当键盘焦点明显不正确时,为什么WPF控件将IsKeyboardFocused设置为true?

您没有做错任何事情;这是WPF已知的一个怪癖

当控件接收到逻辑焦点时,WPF也会尝试给它键盘焦点但是当您在非活动WPF应用程序中分配键盘焦点时,该应用程序的行为就好像它是活动的一样。这意味着,除其他外,聚焦的
文本框
将显示闪烁的插入符号,
IsKeyboardFocused
和相关属性将被设置

我在过去看到过这个问题,重复这个问题是微不足道的

Xaml:

<Window x:Class="WpfTest.FocusTest"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
  <Grid>
    <StackPanel HorizontalAlignment="Center"
                VerticalAlignment="Center">
      <TextBox x:Name="_textBox"
               Width="150">
        <TextBox.Style>
          <Style TargetType="{x:Type TextBox}">
            <Style.Triggers>
              <Trigger Property="IsKeyboardFocused"
                       Value="true">
                <Setter Property="Background"
                        Value="Lavender" />
                <Setter Property="BorderBrush"
                        Value="Blue" />
              </Trigger>
            </Style.Triggers>
          </Style>
        </TextBox.Style>
      </TextBox>
      <Button Margin="0,7,0,0"
              Content="_Click Me"
              Click="OnButtonClick" />
    </StackPanel>
  </Grid>
</Window>
public partial class FocusTest
{
    public FocusTest()
    {
        InitializeComponent();
    }

    private void OnButtonClick(object sender, RoutedEventArgs e)
    {
        _textBox.Text = "";

        // NOTE: Requires System.Reactive.Core, available in NuGet.
        System.Reactive.Concurrency.Scheduler.Default.Schedule(
            TimeSpan.FromSeconds(5),
            () => this.Dispatcher.BeginInvoke(new Action(this.SetFocus)));
    }

    private void SetFocus()
    {
        _textBox.Text = "Focused";
        FocusManager.SetFocusedElement(_textBox, _textBox);
    }
}
点击按钮,Alt+Tab切换到记事本,等待5秒钟,使
文本框
接收焦点。
IsKeyboardFocused
触发器被触发,闪烁的插入符号出现,但键盘输入仍被发送到记事本

这里的关键点是,只有当一个元素被赋予焦点而另一个应用程序处于活动状态时(因此存在人为延迟),问题才会出现。请注意,如果将
SetFocusedElement
调用替换为
Keyboard.Focus(\u textBox)
\u textBox.Focus()
,以及其他变体,则问题仍然会出现


不幸的是,我不知道有什么可靠的、非黑客的方法来解决这个问题。我不记得我花了多少时间在这上面,但我最终决定不值得这么麻烦。这不是经常出现的问题。

完成最小示例plz。你的例子在我的机器上很好你是什么意思?你完全按照我说的做了吗?是的。点击记事本会将背景变回白色(默认)。您的DataTrigger实际上可能就是问题所在。一个完整的最低限度的例子总是有帮助的,我正在努力。最初点击记事本不是问题。问题在于,当键盘焦点丢失到记事本后,服务触发事件将焦点放回控件中。问题是,即使触发器将其点亮,键盘焦点也不会真正回到控件中。我必须用后台服务编写一些代码来复制这个问题,然后我会发布一个github链接到它。创建一个最小的示例需要一点时间,但当我有一个链接时,我会用一个链接编辑这个问题。我在回答中包含了一个最小的示例,它可靠地再现了Windows 7上的问题。这是一个古老的、已知的问题(至少我是知道的)。当你陈述解决这个问题的非黑客方式时,你的确切意思是什么?“修复”是指使IsKeyboardFocused在其他应用程序处于活动状态时保持为false,还是有办法使我自己的应用程序也处于活动状态?也许这里真正的问题是另一个应用程序处于活动状态,但我希望我的应用程序被激活。另一方面,也许我想要的不是一个合适的设计。@shawn1874我只是说我花了时间试图“修复”这个问题,但我没有想出一个可接受的解决方案。我不记得我是找到了一个黑客解决方案还是根本找不到解决方案。“修复”应该是“修复它,这样应用程序就不会表现得像有键盘焦点,而实际上没有”。我认为你不能得到你想要的行为。至少由于Windows Vista/7,您的应用程序只能在以下情况下更改前景窗口:(1)您的应用程序处于活动状态;或者(2)活动应用程序已授予您的应用程序更改前景窗口的权限。确定。我找到了一种方法,将我的应用程序窗口设置为相关用例的活动窗口。因为我只在发现一个设备后做一次,它就完成了我需要的,并且防止了这个奇怪的问题发生。我的目标是windows 7,但听起来你好像在暗示,这对运行在windows 8或10上的应用程序不起作用。@shawn1874我的理解是,它也不应该在windows 7上起作用。据我所知,您只能从当前活动的应用程序设置前景窗口(1),或(2)当前活动的应用程序授予您这样做的权限时,例如,通过调用Win32方法
AllowSetForegroundWindow
。也许我弄错了,但是当我有单独的应用程序和启动程序进程时,我只能让应用程序自己进入前台,如果启动程序进程明确地允许它这样做的话。但是,嘿,如果你让它工作了,那就太好了:)@shawn1874另外,确保你测试时有没有附加调试器。