为什么从代码后面设置键盘焦点需要Dispatcher.BeginInvoke?

时间:2012-12-13 12:03:38

标签: c# wpf user-controls textbox dispatcher

我的UserControl包含TextBox。当用户控件变为可见时,我会给出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);
    }
}

3 个答案:

答案 0 :(得分:3)

您可以在Keyboard.Focus(InputTextBox);而不是InputTextBox.IsVisibleChanged的事件处理程序中调用this.IsVisibleChanged吗?

如果这样可行,那么我怀疑在布局面板更新了子控件之前引发了this.IsVisibleChanged事件,也就是说当你将注意力集中在InputTextBox时,BeginInvoke仍然不可见}。

答案 1 :(得分:2)

可能是因为IsVisibleChanged事件是在另一个线程上引发的(而不是在UI线程上)。

答案 2 :(得分:1)

您正在操作的控件属于UI线程(因为它是创建它的位置)。所有控件都派生自DispatcherObject,因此control.Dispatcher(或控件中的this.Dispatcher)将为您提供对属于创建控件的线程的Dispatcher的引用。

然后,您将从运行事件处理程序的后台线程对该Dispatcher上的操作进行排队。你为什么要在后台线程上运行?它是一个控件,所以它受其主机的支配,猜测后台线程上有一些编程逻辑导致可见性发生变化(可能通过数据绑定),因此也会调用事件处理程序背景线程。

为了阻止你与Dispatcher狂野并试图用它来执行它不适合的神奇神秘功能,请确保你熟悉Dispatcher.CurrentDispatcher属性及其差异(由于开发人员没有意识到这一点,我看到了一些非常糟糕的代码。

有关与UI元素关联的Dispatcher的概述,请查看以下文章:MSDN Advanced WPF: Threading Model。请注意,在尝试操作控件的操作之前调用VerifyAccess()的示例代码。