欧美日韩不卡一区二区三区,www.蜜臀.com,高清国产一区二区三区四区五区,欧美日韩三级视频,欧美性综合,精品国产91久久久久久,99a精品视频在线观看

WPF怎樣在工作線程中更新窗體的UI元素Dispa

時(shí)間:2025-01-29 00:17:19 好文 我要投稿
  • 相關(guān)推薦

WPF怎樣在工作線程中更新窗體的UI元素Dispa

  這是一個(gè)普遍的問題:如果我們?cè)俪绦蛑惺褂昧硕嗑程技術(shù),而工作線程(后臺(tái)線程)如果需要更新界面上的元素(例如進(jìn)度條等),就會(huì)有一個(gè)線程安全性問題,因?yàn)檫M(jìn)度條是由主線程創(chuàng)建出來的。

  關(guān)于這一點(diǎn),大致上看,WPF的機(jī)制與Windows Forms是沒有差別的。我們?cè)赪indows Forms中需要按照下面的方式更新窗體元素。

  using System;using System.Windows.Forms;using System.Threading;namespace WindowsFormsApplication1{public partial class Form1 : Form{public Form1(){InitializeComponent();}private void button1_Click(object sender, EventArgs e){//錯(cuò)誤的寫法:直接更新new Thread(() =>{progressBar1.Value = 10;}).Start();}private void button2_Click(object sender, EventArgs e){//正確的寫法,通知主線程更新new Thread(()=>{this.Invoke(new Action(() =>{progressBar1.Value = 10;}));}).Start();}}}

  第一種是錯(cuò)誤的寫法,它將導(dǎo)致一個(gè)運(yùn)行時(shí)錯(cuò)誤

  了解了這些,我們來看看WPF是怎么做的?

  點(diǎn)擊第一個(gè)按鈕的話,我們同樣會(huì)收到一個(gè)錯(cuò)誤

  點(diǎn)擊第二個(gè)按鈕,則工作正常

  我們看看代碼有什么區(qū)別

  using System;using System.Windows;using System.Threading;namespace WpfApplication1{///

  /// Window1.xaml 的交互邏輯///

  public partial class Window1 : Window{public Window1(){InitializeComponent();}private void button1_Click(object sender, RoutedEventArgs e){//錯(cuò)誤的寫法:直接更新new Thread(() =>{progressBar1.Value = 20;}).Start();}private void button2_Click(object sender, RoutedEventArgs e){//正確的寫法:通知主線程去完成更新new Thread(()=>{this.Dispatcher.Invoke(new Action(()=>{progressBar1.Value=20;}));}).Start();}}}

  請(qǐng)注意,Window類并沒有Invoke方法,這是與Form不一樣的。取而代之的是,我們需要通過訪問Window.Dispatcher屬性,然后調(diào)用Invoke方法 。僅此而已

  好吧,那么到底什么是Dispatcher呢?從字面上來說,它是所謂的接線員,或者調(diào)度員的意思。這說明什么呢?每個(gè)線程都有一個(gè)唯一的調(diào)度員,我們?cè)诖a中所做的工作其實(shí)是向這個(gè)調(diào)度員發(fā)出指令,然后它再幫我們做。這樣理解就對(duì)了。

  我們的窗體是在主線程創(chuàng)建出來的,里面的控件自然也是如此。我們之前解釋過WPF的應(yīng)用程序也是單線程模型的(STAThread),所以整個(gè)應(yīng)用程序里面會(huì)有一個(gè)默認(rèn)的Dispatcher,它負(fù)責(zé)調(diào)度主線程的工作。

  其實(shí),如果大家真有興趣,可以看看Application.Run這個(gè)方法的實(shí)現(xiàn),就能理解上面所說的話了

  [SecurityCritical]internal int RunInternal(Window window){base.VerifyAccess();EventTrace.NormalTraceEvent(EventTraceGuidId.APPRUNGUID, 0);if (this._appIsShutdown){throw new InvalidOperationException(SR.Get("CannotCallRunMultipleTimes", new object[] { base.GetType().FullName }));}if (window != null){if (!window.CheckAccess()){throw new ArgumentException(SR.Get("WindowPassedShouldBeOnApplicationThread", new object[] { window.GetType().FullName, base.GetType().FullName }));}if (!this.WindowsInternal.HasItem(window)){this.WindowsInternal.Add(window);}if (this.MainWindow == null){this.MainWindow = window;}if (window.Visibility != Visibility.Visible){base.Dispatcher.BeginInvoke(DispatcherPriority.Send, delegate (object obj) {(obj as Window).Show();return null;}, window);}}this.EnsureHwndSource();if (!BrowserInteropHelper.IsBrowserHosted){this.RunDispatcher(null);}return this._exitCode;}[SecurityCritical]private object RunDispatcher(object ignore){Invariant.Assert(!this._ownDispatcherStarted);this._ownDispatcherStarted = true;Dispatcher.Run();return null;}那么,為什么在Window中可以調(diào)用到Dispatcher屬性呢?或者說在那些對(duì)象上面可以采用這種機(jī)制呢?大致上說,幾乎所有的控件都可以,因?yàn)樗麄兊幕愐话愣伎梢宰匪莸揭粋(gè)DispatcherObject

  從這個(gè)角度來說,如果我們自己編寫一個(gè)用于WPF的控件,那么也是需要按照這樣的層次結(jié)構(gòu)去繼承的。這樣在控件內(nèi)部,才可以通過this.Dispatcher來更新一些界面元素了。

  那么,如果我們是一個(gè)類庫(kù)項(xiàng)目,就是一個(gè)標(biāo)準(zhǔn)的類型,它也需要更新到主線程中的一些元素怎么辦?

  此時(shí)可以通過Application.Current.Dispacther來實(shí)現(xiàn),例如下面的例子

  using System;using System.Windows;namespace WpfApplication1{public class WindowHelper{public static void SomeMethod() {Application.Current.Dispatcher.Invoke(new Action(() => {Application.Current.MainWindow.Title = "我修改過的窗體標(biāo)題";}));}}}

  其實(shí),要認(rèn)真講的話,Application的這個(gè)Dispatcher與我們剛才用到的Window的Dispatcher是同一個(gè)對(duì)象。也就是說,每個(gè)線程只有一個(gè)。

  而其實(shí),使用Window的Dispatcher,與使用Button的Dispatcher也沒有區(qū)別的

  最后要說一點(diǎn)的是,Dispatcher除了Invoke方法之外,還有BeginInvoke方法。區(qū)別在于后者是異步執(zhí)行的。如何使用異步的機(jī)制呢?

  using System;using System.Windows;using System.Windows.Threading;namespace WpfApplication1{public class WindowHelper{public static void SomeMethod() {//Application.Current.Dispatcher.Invoke(new Action(() => {//    Application.Current.MainWindow.Title = "我修改過的窗體標(biāo)題";//}));var task = Application.Current.Dispatcher.BeginInvoke(new Action(() => { Application.Current.MainWindow.Title = "我修改過的窗體標(biāo)題"; }));task.Completed += new EventHandler(task_Completed);}static void task_Completed(object sender, EventArgs e){MessageBox.Show("任務(wù)已經(jīng)完成");}}}

【W(wǎng)PF怎樣在工作線程中更新窗體的UI元素Dispa】相關(guān)文章:

怎樣在工作中脫穎而出怎樣在工作中步步高升08-20

工作中的倦怠情緒是怎樣煉成的08-09

怎樣把握交際中的冷熱10-23

細(xì)胞中的元素和化合物知識(shí)點(diǎn)03-02

怎樣在工作中獲得幸福感06-13

怎樣去除生活中的各種異味09-09

30歲男人繁忙工作中該怎樣養(yǎng)生06-27

怎樣在多個(gè)offer中做出選擇呢08-01

工作中怎樣才不浪費(fèi)時(shí)間05-29