[英]Why do I need a UI Thread check
要從其他線程更新UI,您需要調用調度程序的BeginInvoke方法。 在調用方法之前,可以檢查調用線程是否與調度程序關聯。
對於我的示例,我有兩種更新文本框的方法; 通過單擊按鈕並設置計時器。 編碼:
using System;
using System.Timers;
using System.Windows;
using System.Windows.Controls;
namespace WpfApplication1
{
public partial class MainWindow : Window
{
private int i = 0;
private TextBlock myText = new TextBlock();
private Button myButton = new Button();
private Timer timer = new Timer(2 * 1000);
private StackPanel panel = new StackPanel();
public MainWindow()
{
InitializeComponent();
myButton.Content = "Click";
panel.Children.Add(myText);
panel.Children.Add(myButton);
this.AddChild(panel);
myButton.Click += (_, __) => IncrementAndShowCounter();
timer.Elapsed += (_, __) => IncrementAndShowCounter();
timer.Start();
}
private void IncrementAndShowCounter()
{
i++;
if (this.Dispatcher.CheckAccess())
{
myText.Text = i.ToString();
}
else
{
this.Dispatcher.BeginInvoke((Action)(() =>
{
myText.Text = i.ToString();
}));
}
}
}
}
當我不使用CheckAccess()並始終執行BeginInvoke時,一切正常。
所以我的問題是為什么不總是使用BeginInvoke並跳過CheckAccess?
所以我的問題是,為什么不總是使用
BeginInvoke
並跳過CheckAccess
?
在需要調用的情況下 (即您正在觸摸另一個線程擁有的控件),這就是大多數時候應該做的事情。 如果不需要調用,則應將它們都跳過。
使用CheckAccess
意味着您的代碼不知道或不想假設它將在“正確”線程上運行。 造成這種情況的主要原因有兩個:通用性(您的代碼在庫中,並且您無法預測其用法)和便利性(您只希望使用一種方法來處理這兩種情況,或者希望自由更改)操作模式而不破壞程序)。
您的示例屬於第二類:相同的方法可同時服務於兩種操作模式。 在這種情況下,您有三個可能的選擇:
始終在沒有CheckAccess
情況下調用。
這將給您帶來性能上的損失(在這里可以忽略不計),並且還將使代碼閱讀器假定該方法僅從工作線程中調用。 由於唯一的好處就是您將編寫更少的代碼,所以這是最糟糕的選擇。
保持一切不變。
由於從UI線程和輔助線程都調用了IncrementAndShowCounter
,因此使其適應情況可以使您繼續處理其他問題。 這很簡單,也很好。 這也是編寫庫代碼時所做的最好的事情(不允許假設)。
切勿從方法內部調用,請根據需要從外部進行調用。
這是技術上的最佳選擇:由於您知道將在其中調用該方法的上下文,因此請安排在該方法之外進行調用。 這樣,該方法就不會綁定到任何特定的線程,並且您不會受到不必要的性能損失。
這是第三個選項的示例代碼:
private void IncrementAndShowCounter()
{
i++;
myText.Text = i.ToString();
}
myButton.Click += (_, __) => IncrementAndShowCounter();
timer.Elapsed += (_, __) => Dispatcher.BeginInvoke(IncrementAndShowCounter);
如果您100%確保調用線程是UI線程-您可以直接使用“ DO”方法。
如果您100%確定調用線程不是UI線程,但是該操作應在UI線程上完成,則只需調用BeginInvoke
....
// 100% I'm sure the Click handler will be invoked on UI thread
myButton.Click += (_, __) => IncrementAndShowCounter();
// here I'm not sure
timer.Elapsed += (_, __) => Dispatcher.BeginInvoke(IncrementAndShowCounter);
// 100% not UI thred here:
Task.Factory.StartNew(() => Dispatcher.BeginInvoke(IncrementAndShowCounter), TaskScheduler.Default)
private void IncrementAndShowCounter()
{
i++;
myText.Text = i.ToString();
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.