zoukankan      html  css  js  c++  java
  • WPF:浅析Dispatcher

    本人文笔差。还是直接上代码吧。(本文假设你对WPF中的Dispatcher有一定的了解)

    你觉得下面的代码可以正常执行吗?

            private void Button_Click(object sender, RoutedEventArgs e)
            {
                Thread t = new Thread(() =>
                {
                    while (true)
                    {
                        new Window().Show();
                        Thread.Sleep(1000);
                    }
                });
                t.Start();
            }

    WPF的操作UI的线程必须是单线程单元模型(STA),也就是必须把线程的单元状态设置为STA才可以操作UI对象。

    上面的代码,并没有设置线程的单元状态,线程的默认单元状态为:System.Threading.ApartmentState.Unknown

    通过下面的代码可以设置线程的单元状态为STA:

    t.TrySetApartmentState(ApartmentState.STA);

    修改后的代码如下:(可以正常运行)

            private void Button_Click(object sender, RoutedEventArgs e)
            {
                Thread t = new Thread(() =>
                {
                    while (true)
                    {
                        new Window().Show();
                        Thread.Sleep(1000);
                    }
                });
                t.TrySetApartmentState(ApartmentState.STA);
                t.Start();
            }

    接下来,对代码再做一点修改,你觉得下面的代码是否可以正常运行呢?

            private void Button_Click(object sender, RoutedEventArgs e)
            {
                Thread t = new Thread(() =>
                {
                    while (true)
                    {
                        Window win = new Window();
    
                        this.Dispatcher.Invoke(new Action(delegate
                            {
                                win.Show();
                            }));
                        Thread.Sleep(1000);
                    }
                });
    
                t.TrySetApartmentState(ApartmentState.STA);
                t.Start();
            }

     在一个线程中创建的UI对象,也只能是创建该UI对象的线程才能访问它。如果其他线程要访问这个UI对象,需要通过创建UI线程的Dispatcher才能实现。

    上面的代码,win对象实际上是t这个线程创建的。而执行win.Show()这个动作的却是另外这个线程(实际上是主UI线程),所以上面的代码也是不能正常执行的。

    需要注意的是,只有当一个线程中执行过UI操作后,这个线程才具有Dispatcher,然后其他线程可以通过这个Dispatcher去访问该线程创建的UI对象。一个没有执行任何UI操作的线程,其Dispatcher为null.

    通过Dispatcher的静态方法FromThread可以获取一个线程关联的Dispatcher对象。如果你觉得上面的这句话不好理解,可以看看下面的图:

    看以看到,在没有执行UI操作之前,线程t的Dispatcher对象的值为null,当执行完Window win = new Window();后(也就是执行了一个UI操作),t线程关联的Dispatcher就有值了。

    总结:

    1. 任何线程中如果想执行UI操作,那么其线程单元必须设置为STA。
    2. 一个线程如果创建了UI对象,那么这个UI对象就只能被这个线程管理。
    3. 任何线程如果需要访问其他的线程创建的UI对象,只能通过其他线程的Dispatcher进行访问
    4. 一个线程如果没有执行任何UI操作,那么其关联的Dispatcher为null
  • 相关阅读:
    centos7.9安装Oracle 19c数据库(rpm方式)
    tomcat配置404/500自定义错误页面
    centos7.7部署多个tomcat服务器
    Linux配置Tomcat实现双向SSL认证(使用keytool工具生成证书)
    C#方法的多值返回方式
    Unity 判断2D/3D坐标系下的一个点是否在指定的摄像机视野范围内
    Unity项目的APK在雷电模拟器上弹出 "XXX停止运行"或者“XXX屡次停止运行”
    Python调用Unity工程下CSharp代码中的静态方法
    C#如何屏蔽程序的多次启动
    Something about My Blog
  • 原文地址:https://www.cnblogs.com/DoNetCoder/p/4369903.html
Copyright © 2011-2022 走看看