何时是分配给线程的UI元素

时间:2013-08-08 20:07:43

标签: c# .net wpf multithreading

我知道我以前看过一篇文章或者上面的内容,但现在似乎无法找到它。我遇到了一个问题,帮助一个同事编写了一个测试,该测试检查了多个线程中发生的UI操作(我意识到这里的问题......这不是我现在想要关注的:))。代码看起来类似于这种伪代码:

[RequiresSTA]
Test
{
  var tb = new Textbox();
  tb.DoSomethingAsyncAndThenUpdateTB() //This is done via tb.SetValue being called
}

...

DoSomethingAsyncAndThenUpdateTB()
{
  var bw = new BackgroundWorker();
  bw.DoWork += ...Do Stuff...
  bw.RunWorkerCompleted += { tb.Text = "foo";}
}

我遇到的问题是OnComplete抛出了一个跨线程异常。但是,应该在STA线程上创建所有内容。我相信问题是UI元素不是在创建时附加到他们的线程上,而是在稍后的点....并且我的文本框最终附加到不是STA的线程?或者也许是背景工作者?

问题:

UI元素何时实际附加到线程?

2 个答案:

答案 0 :(得分:2)

首先,不只有一个STA线程。任何线程都可以在创建时创建为 STA线程。 UI线程需要是STA线程,但并非所有STA线程都是UI线程。

接下来,您遇到BackgroundWorker需要知道UI线程是什么的问题。它能够将某些事件封送到UI线程并不神奇。它的作用是在其构造函数中查看SynchronizationContext.Current的值。然后它捕获该上下文的值,并在稍后使用它作为上下文的定义以将所有非工作事件发布到。如果你在UI线程之外创建BGW,那么它以后就无法编组回UI线程。

如果你有一个STA线程用作你的UI线程,但你没有设置SynchronizationContext.Current的值,那么BGW将无法做到这一点。

至于问题:

  

UI元素何时实际附加到线程?

在其构造函数中。

答案 1 :(得分:0)

每个ui元素实现DependencyObject,它实现抽象类DispatcherObject。当创建DispatcherObject时,它将当前调度程序分配给DispatcherObject。 稍后,每当您访问UI元素的任何属性时,都会进行验证,检查您是否从UI线程访问它。

这在VerifyAccess中完成

/// <summary>Enforces that the calling thread has access to this <see cref="T:System.Windows.Threading.DispatcherObject" />.</summary>
    /// <exception cref="T:System.InvalidOperationException">the calling thread does not have access to this <see cref="T:System.Windows.Threading.DispatcherObject" />.</exception>
    [EditorBrowsable(EditorBrowsableState.Never)]
    public void VerifyAccess()
    {
        Dispatcher dispatcher = this._dispatcher;
        if (dispatcher != null)
        {
            dispatcher.VerifyAccess();
        }
    }

如果调用线程不是与调度程序关联的线程,则抛出异常

public void VerifyAccess()

{     if(!this.CheckAccess())     {         抛出新的InvalidOperationException(SR.Get(“VerifyAccess”));     } }

这称为线程亲和力