【发布时间】:2020-03-13 19:48:29
【问题描述】:
我不明白是否必须使用 Dispatcher 通知 UI 线程绑定的属性已由非 UI 线程更新。
从一个基本示例开始,为什么下面的代码没有抛出著名的(我记得在过去的编码经验中为此苦苦挣扎)调用线程无法访问该对象,因为不同的线程拥有它异常? p>
private int _myBoundProperty;
public int MyBoundProperty { get { return _myBoundProperty; } set { _myBoundProperty = value; OnPropertyChanged(); } }
private void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
public void Test()
{
new System.Threading.Thread(() =>
{
try
{
MyBoundProperty += DateTime.Now.Second;
}
catch(Exception ex)
{
}
}).Start();
}
<TextBlock Text="{Binding MyBoundProperty"/>
我看到了一些关于这个主题的帖子,但在我看来它们很混乱:
- 有人说 Dispatcher 对于集合是必需的,但对于单个变量则不需要:那么为什么这个其他示例仍然没有引发异常?
private ObservableCollection<int> _myBoundPropertyCollection;
public ObservableCollection<int> MyBoundPropertyCollection { get { return _myBoundPropertyCollection; } set { _myBoundPropertyCollection = value; OnPropertyChanged(); } }
private void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
public void TestCollection()
{
new System.Threading.Thread(() =>
{
try
{
//MyBoundPropertyCollection = new ObservableCollection() { 0 }; //even so not throwing
MyBoundPropertyCollection[0] += DateTime.Now.Second;
}
catch(Exception ex)
{
}
}).Start();
}
<TextBlock Text="{Binding MyBoundPropertyCollection[0]"/>
- 有人说这是以前的 .NET 版本所要求的:那么现在我们可以删除那些 Dispatcher 调用(我使用的是 .NET Framework 4.7)吗?
- 有人说使用 Dispatcher 是一种很好的做法,即使您的代码没有引发异常:这似乎是一种信仰行为...
【问题讨论】:
-
是的,您需要使用 Dispatcher 来更新 WPF 控件。如有疑问,请阅读documentation。
-
@Zer0 所以这只是一个随机且特定的场景,上面提供的代码没有抛出异常(在重复的测试运行中)?难以置信.....
-
这并不罕见。自 WinForms 以来,这个线程问题一直存在。我建议您了解为什么需要用
[STAThread]标记 WPF GUI 线程。仅仅因为控件在从后台线程更新时不会引发异常,not 就使其成为一个好主意。一直不安全。
标签: c# wpf multithreading data-binding dispatcher