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

本文关键字:UI 元素 线程 分配 何时 | 更新日期: 2023-09-27 18:27:07

我知道我以前看过关于这方面的文章或SO,但现在似乎找不到了。我在帮助一位同事编写测试时遇到了一个问题,该测试正在检查跨多个线程发生的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元素什么时候真正附加到线程?

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

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

接下来,BackgroundWorker需要有某种方式来了解UI线程是什么。它能够将某些事件封送到UI线程,这并不神奇。它所做的是在构造函数中查看SynchronizationContext.Current的值。然后,它捕获该上下文的值,并在以后将其用作将所有非工作事件发布到的上下文的定义。如果在UI线程之外创建BGW,那么它以后将无法封送回UI线程。

如果您有一个STA线程用作UI线程,但尚未设置值SynchronizationContext.Current,则BGW将无法执行其任务。

关于的问题

UI元素什么时候真正附加到线程?

在其构造函数中。

每个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"));}}

这被称为线程相关性