线程同步 SynchronizationContext 在命令行程序中创建一个ui线程承载WPF运行

1、创建一个线程作为ui线程

ui线程要求必须是STA线程

        var t = new Thread(() => {


        });

        t.SetApartmentState(ApartmentState.STA);
        t.Start();

2、创建一个公共的SynchronizationContext作为同步的入口

在.NET框架中,Dispatcher是一个类,它负责接收和处理特定线程的消息队列,这通常在WPF应用程序的UI线程中使用。Dispatcher.CurrentDispatcher返回与当前线程关联的Dispatcher对象。

DispatcherSynchronizationContext是SynchronizationContext的一个实现,它使用Dispatcher来排队和执行工作项。这是在WPF中使用的,以确保只有在正确的线程(通常是UI线程)上才执行UI操作。

因此,这行代码:

uiContext = new DispatcherSynchronizationContext(Dispatcher.CurrentDispatcher);
创建了一个新的DispatcherSynchronizationContext实例,该实例与当前线程的Dispatcher关联。这样,当你使用uiContext.Post或uiContext.Send方法排队工作项时,它们将通过Dispatcher在正确的线程上执行。

然后,SynchronizationContext.SetSynchronizationContext(uiContext);将新创建的DispatcherSynchronizationContext设置为当前线程的同步上下文。这样,后续的异步操作可以使用这个同步上下文来排队工作项,以确保它们在正确的线程上执行。

总的来说,这些代码确保了在UI线程上执行UI操作,从而避免了多线程环境中的竞争条件和数据不一致问题。

 

            uiContext = new DispatcherSynchronizationContext(Dispatcher.CurrentDispatcher);
            SynchronizationContext.SetSynchronizationContext(uiContext);

 

3、开启消息循环

System.Windows.Threading.Dispatcher.Run() 是一个静态方法,它开始执行与当前线程关联的 Dispatcher 的事件循环。在 WPF 中,每个 UI 线程都有一个 Dispatcher,并且 Dispatcher.Run() 用于开始处理该 Dispatcher 的消息队列。

在一个典型的 WPF 应用程序中,当你启动应用程序时,主 UI 线程的 Dispatcher.Run() 方法会被自动调用,这使得主 UI 线程可以开始处理事件,例如用户输入、绘图命令等。

在你的情况下,你创建了一个新的 STA 线程并希望它能够处理 UI 事件。为了实现这一点,你需要在该线程上调用 Dispatcher.Run(),以开始处理与该线程关联的 Dispatcher 的消息队列。

注意,Dispatcher.Run() 是一个阻塞方法,这意味着它会一直运行,直到调度程序的队列被关闭(例如,通过调用 Dispatcher.BeginInvokeShutdown 或 Dispatcher.InvokeShutdown 方法)或应用程序终止。这就是为什么你通常会在线程的主循环中看到 Dispatcher.Run() 被调用,因为这意味着线程将一直存在,直到应用程序结束或调度程序队列被明确关闭。

System.Windows.Threading.Dispatcher.Run();

 

4、控制此线程的生命周期

        uiContext.Post(state => {

            Dispatcher.CurrentDispatcher.InvokeShutdown();
        },null);

 

 

全部代码

class Program 
{
    [STAThread]
    static void Main(string[] args) 
    {
        SynchronizationContext uiContext = null;

        var t = new Thread(() => {

            uiContext = new DispatcherSynchronizationContext(Dispatcher.CurrentDispatcher);
            SynchronizationContext.SetSynchronizationContext(uiContext);
            System.Windows.Threading.Dispatcher.Run();

            Console.WriteLine("2222");
        });

        t.SetApartmentState(ApartmentState.STA);
        t.Start();

        //while (t.IsAlive) 
        //{
        //    Thread.Sleep(100);
        //}

        // 在主线程上等待 UI 线程准备好
        while (uiContext == null)
        {
            Thread.Sleep(100);
        }

        uiContext.Post(state => 
        { 
            var winTest=new WinTest();
            winTest.Show();

        },null);

        uiContext.Post(state => {

            Dispatcher.CurrentDispatcher.InvokeShutdown();
        },null);




        while (true) 
        {
            Thread.Sleep(1000);
            Console.WriteLine(111);
        }

    }

}

 

posted @ 2024-03-20 15:17  卖雨伞的小男孩  阅读(32)  评论(0编辑  收藏  举报