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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM