我们有一个自定义控件,它在其 LostFocus 事件中有一些“提交”逻辑,如果用户移动到应用程序的不同部分,该事件就会触发。
出现问题的原因是工具栏和应用程序的其他区域上的多个按钮的“Focusable”属性设置为 False。因此,当它们被点击时,它们各自的动作就会触发,但我们的控件仍然没有提交它的更改,这会导致问题。
由于我们的 UI 本质上是模块化/动态的,并且因为它只是一种很好的编码实践,这些区域彼此不知道,因此我们不能简单地在按钮处理程序中添加代码来使我们的控件提交。我们的控件需要意识到点击了自身之外的东西。
我们最初的尝试是在我们控件的 GotFocus 中使用类级别的事件处理程序,就像这样......
EventManager.RegisterClassHandler(
typeof(FrameworkElement),
PreviewMouseDownEvent,
new RoutedEventHandler(MyControl_PreviewMouseDownHandler));
private void MyControl_PreviewMouseDown(object sender, RoutedEventArgs e)
{
// Exit if the sender isn't the original source.
// This is because we want the deepest-clicked item, but also only want to process this once
if(sender != e.OriginalSource)
return;
var frameworkElement = (FrameworkElement)sender;
// If the clicked item is a descendant of ThisControl, do nothing.
if(frameworkElement.IsDescendantOf(NameOfMyControlInstance))
return;
CommitChanges();
// Unsubscribe class handler here
??? Can't do!
}
如果我们的控制失去焦点,我们只需提交更改并取消订阅。此外,如果处理程序被触发但 OriginalSource 不在我们的控制范围内,我们还将提交我们的更改并取消订阅处理程序。问题是您不能取消订阅类处理程序!为什么我不知道。
那么我们如何判断用户在我们控制之外点击了不会窃取焦点的东西呢?