Wpf中Dispatcher.Invoke和Dispatcher.BeginInvoke的區別
阿新 • • 發佈:2022-03-07
看下面的程式碼:
new Thread(()=> { Application.Current.Dispatcher.BeginInvoke(new Action(() => { while (true) { Thread.Sleep(1000); } }), null); Console.WriteLine("test"); }).Start();
這段程式碼,會在控制檯列印test,然後介面會一直卡住。介面卡住,說明while迴圈是在ui執行緒執行的,能夠列印test,說明在執行Application.Current.Dispatcher.BeginInvoke時並沒有阻塞當前介面,如果把BeginInvoke改成Invoke,那麼test將不會被列印,說明Invoke方法的邏輯是把委託交給ui執行緒執行,並阻塞當前執行緒,直到委託結束。而BeginInvoke方法則首先新開一個執行緒,那新開的執行緒,再將委託交給ui執行緒處理。注意,最終執行委託的執行緒都是ui執行緒。所以,BeginInvoke由於有個新開執行緒的過程,不會阻塞當前執行緒。但仍然會阻塞介面。
另外BeginInvoke是可以指定優先順序的,通過方法BeginInvoke(DispatcherPriority, Delegate)來設定優先順序。
//------------------------------------------------------------------------------------------------------------------
UI卡頓假死問題轉載於:https://www.cnblogs.com/YYkun/p/10782653.html
誤區1:使用不同的執行緒操作UI控制元件和耗時操作(即,跨執行緒操作UI控制元件CheckForIllegalCrossThreadCalls=
false
;
),
注意:此處只是為了記錄......
原始同步操作如下所示:
private void button1_Click(object sender, EventArgs e) { Waintting waitting = new Waintting(); waitting.Show(); Thread.Sleep(5000);//模擬等待 MessageBox.Show("連線資料庫成功", "資訊", MessageBoxButtons.OK, MessageBoxIcon.Information); waitting.BeginInvoke((Action)waitting.Close);//BeginInvoke方法返回UI執行緒更新UI介面控制元件的機制。 }
private void btnWatting_Click(object sender, EventArgs e) { Waintting waitting = new Waintting(); waitting.Show(); Task.Factory.StartNew(() => // 將阻塞執行緒的操作在另外一個執行緒中執行,這樣就不會堵塞UI執行緒。 { Thread.Sleep(5000);//模擬等待 MessageBox.Show("連線資料庫成功", "資訊", MessageBoxButtons.OK, MessageBoxIcon.Information); waitting.BeginInvoke((Action)waitting.Close);//BeginInvoke方法返回UI執行緒更新UI介面控制元件的機制。 }); }
調整後非同步方式如下所示:
private void WattingTest2_Click(object sender, EventArgs e) { Func<string> wait = () => { Thread.Sleep(5000);//模擬耗時操作,例如資料庫操作等 return "abc"; }; wait.BeginInvoke(new AsyncCallback(result => { string rst = wait.EndInvoke(result); this.Invoke((Action)(() => this.textBox1.AppendText(rst))); }), null); }
// 盲區--------------------------------------------------
this.progressBar1.Dispatcher.BeginInvoke((ThreadStart)delegate { this.progressBar1.Value = 10); }); Dispatcher.BeginInvoke(new Action(delegate { this.progressBar1.Value = 10); })); Dispatcher.Invoke((Action)(() => this.progressBar1.Value = 10); ));