日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > asp.net >内容正文

asp.net

WPF多线程UI更新

發布時間:2023/11/29 asp.net 27 豆豆
生活随笔 收集整理的這篇文章主要介紹了 WPF多线程UI更新 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

前言

  在WPF中,在使用多線程在后臺進行計算限制的異步操作的時候,如果在后臺線程中對UI進行了修改,則會出現一個錯誤:(調用線程無法訪問此對象,因為另一個線程擁有該對象。)這是很常見的一個錯誤,一不小心就會有這個現象。在WPF中,如果不是用多線程的話,例如單線程應用程序,就是說代碼一路過去都在GUI線程運行,可以隨意更新任何東西,包括UI對象。但是使用多線程來更新UI就可能會出現以上所說問題,怎么解決?本文章提供兩個方法:Dispatcher(大部分人使用),TaskScheduler(任務調度器)。

?

問題再現

  可能有的WPF新手不懂這是什么情況,先來個問題的再現,再使用本文章的兩個方法進行解決。

  為了演示方便,我使用了最簡單的布局,一個開始按鈕,三個TextBlock。按一下開始按鈕,開一個后臺線程隨機得到一個數字,并且更新第一個TextBlock。再開另外一個后臺線程得到另外一個數字,更新第二個TextBlock。第三個TextBlock處理同理。

  XAML代碼:

<Window x:Class="UpdateUIDemo.MainWindow"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"Title="MainWindow" Height="130" Width="363"><Canvas><TextBlock Width="40" Canvas.Left="38" Canvas.Top="27" Height="29" x:Name="first" Background="Black" Foreground="White"></TextBlock><TextBlock Width="40" Canvas.Left="128" Canvas.Top="27" Height="29" x:Name="second" Background="Black" Foreground="White"></TextBlock><TextBlock Width="40" Canvas.Left="211" Canvas.Top="27" Height="29" x:Name="Three" Background="Black" Foreground="White"></TextBlock><Button Height="21" Width="50" Canvas.Left="271" Canvas.Top="58" Content="開始" Click="Button_Click"></Button></Canvas> </Window>

  后臺代碼:

public partial class MainWindow : Window{public MainWindow(){InitializeComponent();}private void Button_Click(object sender, RoutedEventArgs e){Task.Factory.StartNew(Work);}private void Work(){Task task = new Task((tb) => Begin(this.first), this.first);Task task2 = new Task((tb) => Begin(this.second), this.first);Task task3 = new Task((tb) => Begin(this.Three), this.first);task.Start();task.Wait();task2.Start();task2.Wait();task3.Start();}private void Begin(TextBlock tb){int i=100000000;while (i>0){i--;}Random random = new Random();String Num = random.Next(0, 100).ToString();tb.Text = Num;}}

   ?運行一下,在點擊開始按鈕的時候,得到了一個錯誤信息:

  果然不出所料,Begin函數是在后臺線程執行的,tb這個TextBlock是前臺UI線程的對象,所以無法在后臺線程改變UI線程擁有的對象,很多有點經驗的WPF程序員就會使用下面我要說的Dispatcher了!

?

問題解決

  方法一:Dispatcher

    1.把UI更新的代碼放到一個函數中:

private void UpdateTb(TextBlock tb, string text){tb.Text = text;}

    2.使用Dispatcher,大家看修改后的Begin函數(紅色內容):

private void Begin(TextBlock tb){int i=100000000;while (i>0){i--;}Random random = new Random();String Num = random.Next(0, 100).ToString();Action<TextBlock, String> updateAction = new Action<TextBlock, string>(UpdateTb);tb.Dispatcher.BeginInvoke(updateAction,tb,Num);}

  再運行一次程序,可以看到能正常顯示了,并且不會出現假死現象。

  方法二:任務調度器(TaskScheduler)

    有很多任務調度器,在CLR Var C#中就提出了線程池任務調度器,I/O任務調度器,任務限時調度器等,調度器的職責就是負責任務的調度,調節任務執行。同步上下文任務調度器就是該方法二所使用的調度器,其作用是將所有任務都調度給應用程序的GUI線程。

public partial class MainWindow : Window{public MainWindow(){InitializeComponent();}private readonly TaskScheduler _syncContextTaskScheduler = TaskScheduler.FromCurrentSynchronizationContext();private void Button_Click(object sender, RoutedEventArgs e){Task.Factory.StartNew(SchedulerWork);}private void SchedulerWork(){Task.Factory.StartNew(Begin, this.first).Wait();Task.Factory.StartNew(Begin, this.second).Wait();Task.Factory.StartNew(Begin, this.Three).Wait();}private void Begin(object obj){TextBlock tb = obj as TextBlock;int i = 100000000;while (i>0){i--;}Random random = new Random();String Num = random.Next(0,100).ToString();Task.Factory.StartNew(() => UpdateTb(tb, Num),new CancellationTokenSource().Token, TaskCreationOptions.None, _syncContextTaskScheduler).Wait();}private void UpdateTb(TextBlock tb, string text){tb.Text = text;}}

?

   結果展示:

    

總結

  任務調度器還有很多種,按照自己喜歡的方法來實現后臺多線程更新UI。還有任務調度器也可以應用到Winform中。下面提供示例Demo下載。

轉載于:https://www.cnblogs.com/DreamRecorder/p/10823398.html

總結

以上是生活随笔為你收集整理的WPF多线程UI更新的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。