WPF按钮点击后重置焦点

40

我有一个TextBox和一个带有一个ButtonToolBar。如果我在TextBox中输入内容然后点击Button,我希望TextBox失去焦点以便绑定得到更新。我不想给我的TextBox添加UpdateSourceTrigger=PropertyChanged。相反,当我点击Button时,我将焦点重置为主窗口,这样任何其他东西都会失去焦点并更新绑定。

我尝试在按钮上添加OnClick,代码如下,但似乎不起作用:

    private void Button_Click(object sender, RoutedEventArgs e) {
        FocusManager.SetFocusedElement(this, null);
    }
任何建议都会受到赞赏。
谢谢, Raul
4个回答

40

我遇到了类似的问题。当按下回车键时,我需要取消文本框的聚焦状态。最终我用了这段代码:

var scope = FocusManager.GetFocusScope(elem); // elem is the UIElement to unfocus
FocusManager.SetFocusedElement(scope, null); // remove logical focus
Keyboard.ClearFocus(); // remove keyboard focus

我认为这比创建虚拟控件更简洁,而且更具可重用性。尽管如此,我对这个解决方案并不十分自信。但它似乎效果很好。


3
当其他方法都无法强制DatePicker在点击工具栏保存按钮时解析输入的文本时,以下代码对我有效。此代码将视图(MVVM)作为this.owner,并从ViewModel中调用。var t = (DependencyObject)FocusManager.GetFocusedElement(this.Owner); var scope = FocusManager.GetFocusScope(t); FocusManager.SetFocusedElement(scope, null);注:该代码使用了WPF框架的特定语法。 - Dave

28
问题在于工具栏将你的按钮放置在不同的FocusManager.FocusScope中。这意味着,ButtonTextBox可以同时接收逻辑焦点,每个控件都位于自己的范围内。通常这是一件好事情,因为当你选择菜单项和ToolBar按钮时,你通常不希望失去主窗口区域的焦点,但在你的情况下,这正阻止了你正在做的事情。
虽然你可以重写工具栏上的FocusManager.IsFocusScope属性并获得想要的效果,但这可能不是最好的计划,因为它会使所有其他工具栏按钮也从你的主窗口区域中夺取焦点。
相反,你可以使用以下几种简单的解决方案之一:
  • 将你的按钮放在工具栏外部
  • 向主窗口区域添加一个Focusable="true"的控件,并在单击按钮时将其设置为焦点
  • 通过调用textBox.GetBindingExpression(TextBox.TextProperty).UpdateSource()手动强制更新
  • 在主窗口中的控件上临时设置Focusable="true",将焦点集中在它上面,然后立即将Focusable="false"再次设置回去

我尝试过Keyboard.Focus(mainWindow);,但似乎也没有改变焦点。它仍然停留在文本框或者其他被选中的元素上。目前,我只是强制显式地更新元素UpdateSource(),但这似乎不是一个长期可持续的解决方案。我将尝试添加一个ghost控件来设置焦点。 - HaxElit
1
只有在“mainWindow”是Focusable(默认情况下它不是)并且它与TextBox位于相同的FocusScope中时,Keyboard.Focus(mainWindow)才能起作用。尝试在与TextBox相同的容器中创建一个 Focusable="true" 的控件,并将焦点放在该控件上。另一个控件可以是一个简单的 <Control Focusable="true" IsTabStop="false"/>。由于Control没有默认模板,所以它是不可见的。 - Ray Burns
2
感谢提到 FocusManager.IsFocusScope。在我的具体情况下,我想要从我的主窗口区域夺取焦点,所以我只需在我的工具栏上设置 FocusManager.IsFocusScope="False" 即可。 - Aphex

1
我在离开一个日历时遇到了问题,需要点击两次按钮才能离开(WPF, .Net 5.0),我尝试了上面提供的一些解决方案,但没有成功,然而这个解决方案有效——引用自Microsoft网站上的某人:
“我的解决办法是将其插入到主表单中,但这可能有点过度。”
protected override void OnPreviewMouseUp(MouseButtonEventArgs e)
{
  base.OnPreviewMouseUp(e);
  if (Mouse.Captured is Calendar || Mouse.Captured is System.Windows.Controls.Primitives.CalendarItem)
  {
    Mouse.Capture(null);
  }
}

0
我的按钮即使我在鼠标悬停为true/false和isfocused为true/false的App资源中设置了样式触发器,它仍然保持着焦点。我尝试了上述所有方法,并且感谢Visual Studio中的新功能,它提供了访问Github示例的权限,我找到了这个代码片段e.Handled = true; 在我所有的buttonClick方法中,我使用FocusManager.SetFocusedElement(FocusManager.GetFocusScope(xaml按钮名称), null);Keyboard.ClearFocus(); 我的问题按钮在返回到选项卡控件屏幕时具有焦点,这是由Ray Burns提到的不同的FocusManager.FocusScope引起的。选项卡具有焦点,选项卡屏幕上的按钮也具有焦点。通过在buttonClick方法中添加e.Handled = true;,它将焦点保留在选项卡上,这正是我所需要的。

你可能想在回答中提供更多细节和背景。 - mozway
谢谢mozway - 希望编辑能够澄清我的问题和解决方案。 - user3763081

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接