我有一个包含TextBox
的UserControl
。当用户控件变得可见时,我给出TextBox
焦点。有人能澄清一下为什么我必须使用Dispatcher
吗?
public MyUserControl()
{
InitializeComponent();
this.IsVisibleChanged += VisibilityChanged;
}
案例1(工作):
private void VisibilityChanged(object sender, DependencyPropertyChangedEventArgs e)
{
if (this.Visibility == Visibility.Visible)
{
this.Dispatcher.BeginInvoke((Action)delegate
{
Keyboard.Focus(this.InputTextBox);
}, DispatcherPriority.Render);
}
}
情况2(不起作用):
private void VisibilityChanged(object sender, DependencyPropertyChangedEventArgs e)
{
if (this.Visibility == Visibility.Visible)
{
Keyboard.Focus(InputTextBox);
}
}
您能在InputTextBox.IsVisibleChanged
的事件处理程序中调用Keyboard.Focus(InputTextBox);
而不是this.IsVisibleChanged
吗?
如果这有效,那么我怀疑this.IsVisibleChanged
事件是在布局面板更新子控件之前引发的,即当您在没有BeginInvoke
的情况下关注InputTextBox
时,它可能仍然不可见。
可能是因为IsVisibleChanged
事件是在另一个线程上引发的(而不是在UI线程上)。
您正在操作的控件属于UI线程(因为它是在那里创建的)。所有控件都派生自DispatcherObject,因此control.Dispatcher
(或控件内的this.Dispatcher
)将为您提供属于创建控件的线程的Dispatcher的引用。
然后,您正在从事件处理程序运行的后台线程对该Dispatcher上的操作进行排队。为什么要在后台线程上运行?它是一个控件,因此受其主机的支配,猜测后台线程上有一些编程逻辑导致可见性发生变化(可能通过数据绑定),因此事件处理程序也会在该后台线程上调用。
为了防止您疯狂使用Dispatcher,并尝试使用它来执行非预期的神奇神秘壮举,请确保您熟悉Dispatcher。CurrentDispatcher属性及其差异(由于开发人员没有意识到这一点,我看到了一些非常糟糕的代码)。
有关与UI元素关联的Dispatcher的良好概述,请参阅本文:MSDN Advanced WPF:Threading Model。请注意,在尝试操作控件之前调用VerifyAccess()
的示例代码。