wpf 单击某些其他控件时不会引发 TextBox LostFocus
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/16916861/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
TextBox LostFocus is not raised when clicking on certain other controls
提问by Justin
In the following simple WPF application a TextBoxis set to update a property when the focus is lost from that control, like so
在下面的简单 WPF 应用程序中,aTextBox设置为在焦点从该控件上丢失时更新属性,如下所示
<DockPanel>
<ToolBar DockPanel.Dock="Top">
<Button>Test</Button>
</ToolBar>
<TextBox Text="{Binding MyString}" />
</DockPanel>
public MainWindow()
{
InitializeComponent();
DataContext = this;
}
public string MyString
{
get { return _myString; }
set { _myString = value; }
}
However when I run this application, enter some text in the text box and then click on the "Test" button my breakpoint on the MyStringproperty is notraised, also any event handler for the FocusLostevent is not raised either. These events are only raised when focus is lost from the control via some other means (e.g. the window is closed).
但是,当我运行此应用程序时,在文本框中输入一些文本,然后单击“测试”按钮,我的MyString属性上的断点未引发,也未引发该FocusLost事件的任何事件处理程序。这些事件仅在通过某些其他方式(例如窗口关闭)从控件中丢失焦点时才会引发。
This is causing problems for us as in reality the "Test" button contains logic which relies on the MyStringproperty being updated.
这给我们带来了问题,因为实际上“测试”按钮包含依赖于MyString正在更新的属性的逻辑。
How can I ensure that the FocusLostevent is correctly raised and that the binding is updated as I click on the "Test" button? It looks like the problem is somehow caused by the use of the ToolBar, as replacing the ToolBarwith a standard button does not result in this behaviour.
如何确保在FocusLost单击“测试”按钮时正确引发事件并更新绑定?看起来问题是由使用 引起的ToolBar,因为用ToolBar标准按钮替换不会导致这种行为。
采纳答案by Justin
In this case the text box doesn't actually loose logical focus and so the event is never raised - essentially I actually want the LostKeyboardFocusevent, and not the LostFocusevent to trigger the update.
在这种情况下,文本框实际上并没有失去逻辑焦点,因此永远不会引发事件 - 本质上我实际上想要该LostKeyboardFocus事件,而不是LostFocus触发更新的事件。
This issue is similar to WPF: Data bound TabControl doesn't commit changes when new tab is selectedand there is a Microsoft connect item for it herewith a number of potential solutions, however I fixed this using an attached property like so.
这个问题类似于WPF:数据绑定在选择新标签的TabControl不提交更改,有是它的一个微软连接项目在这里与一些可能的解决方案,但我解决了这个使用附加属性,像这样。
public static readonly DependencyProperty BindOnLostKeyboardFocusProperty =
DependencyProperty.RegisterAttached("BindOnLostKeyboardFocus", typeof(bool), typeof(MainWindow), new PropertyMetadata(default(bool), BindOnLostKeyboardFocusChanged));
private static void BindOnLostKeyboardFocusChanged(DependencyObject o, DependencyPropertyChangedEventArgs e)
{
var control = o as UIElement;
if (control != null)
{
if ((bool) e.NewValue)
{
control.AddHandler(LostKeyboardFocusEvent, new RoutedEventHandler(ControlLostKeyboardFocus));
}
else
{
control.RemoveHandler(LostKeyboardFocusEvent, new RoutedEventHandler(ControlLostKeyboardFocus));
}
}
}
private static void ControlLostKeyboardFocus(object sender, RoutedEventArgs e)
{
var control = (UIElement)sender;
control.RaiseEvent(new RoutedEventArgs(LostFocusEvent));
}
This just means that whenever LostKeyboardFocusis raised for that control, it goes ahead and raises an additional LostFocusevent causing the binding to update. Its used like so
这只是意味着每当LostKeyboardFocus为该控件引发时,它都会继续并引发LostFocus导致绑定更新的附加事件。它像这样使用
<TextBox Text="{Binding Test}" LostKeyboardFocus="UIElement_OnLostKeyboardFocus" local:MainWindow.BindOnLostKeyboardFocus="True" />
回答by nmclean
Your attached property makes a couple of assumptions:
您的附加财产做出了几个假设:
- that nothing is depending on the distinction between the
LostKeyboardFocusandLostFocusevents - that the bindings on the element it's attached to will actually respond to the
LostFocusevent (they could have UpdateSourceTrigger.Explicit)
- 没有什么取决于事件
LostKeyboardFocus和LostFocus事件之间的区别 - 它附加到的元素上的绑定实际上会响应
LostFocus事件(它们可能具有UpdateSourceTrigger.Explicit)
Instead, you could enumerate the bindings on the element and directly call UpdateSource:
相反,您可以枚举元素上的绑定并直接调用UpdateSource:
private void CommitBindings(DependencyObject element) {
var localValueEnumerator = element.GetLocalValueEnumerator();
while (localValueEnumerator.MoveNext()) {
var entry = localValueEnumerator.Current;
if (BindingOperations.IsDataBound(element, entry.Property)) {
var bindingExpression = (BindingExpressionBase)entry.Value;
bindingExpression.UpdateSource();
}
}
}
Also, instead of handling each TextBoxindividually, you could handle the container and use OldFocusto get the actual element that lost keyboard focus.
此外,TextBox您可以处理容器并使用OldFocus来获取失去键盘焦点的实际元素,而不是单独处理每个元素。
回答by Matt Sinclair
The following behavior will fix this:
以下行为将解决此问题:
public class TextBoxUpdateOnLostKeyboardFocusBehavior : Behavior<TextBox>
{
protected override void OnAttached()
{
if (AssociatedObject != null)
{
base.OnAttached();
AssociatedObject.LostKeyboardFocus += OnKeyboardLostFocus;
}
}
protected override void OnDetaching()
{
if (AssociatedObject != null)
{
AssociatedObject.LostKeyboardFocus -= OnKeyboardLostFocus;
base.OnDetaching();
}
}
private void OnKeyboardLostFocus(object sender, KeyboardFocusChangedEventArgs e)
{
var textBox = sender as TextBox;
if (textBox != null && e.NewFocus == null)
{
// Focus on the closest focusable ancestor
FrameworkElement parent = (FrameworkElement) textBox.Parent;
while (parent is IInputElement && !((IInputElement) parent).Focusable)
{
parent = (FrameworkElement) parent.Parent;
}
DependencyObject scope = FocusManager.GetFocusScope(textBox);
FocusManager.SetFocusedElement(scope, parent);
}
}
}
You can attach it to your TextBox as follows:
您可以将其附加到您的文本框,如下所示:
<TextBox>
<i:Interaction.Behaviors>
<behaviors1:TextBoxUpdateOnLostKeyboardFocusBehavior />
</i:Interaction.Behaviors>
</TextBox>
回答by UuDdLrLrSs
I had a very similar case where a TextBoxin a Toolbarwas not updating its binding source when the main OK button on the window was clicked. But if you tabbed out first, it would work.
我有一个非常相似的情况,当单击窗口上的主要 OK 按钮时, aTextBox中的 aToolbar没有更新其绑定源。但是,如果您先退出,它会起作用。
In my case I was able to alter the binding to use UpdateSourceTrigger=PropertyChangedand the problem was solved.
就我而言,我能够更改要使用的绑定,UpdateSourceTrigger=PropertyChanged问题就解决了。
This would cause a lot more binding updates than the default binding behavior, but in this case that was not a problem.
这将导致比默认绑定行为更多的绑定更新,但在这种情况下,这不是问题。

