我正在学习跨线程,并且对如何从我创建的类(viewmodel)更新主UI线程有疑问。从我收集的信息来看,调度员是可行的方式。如何在类中使用主UI线程调度程序?或者有更好的方法来做到这一点。在这个例子中,我将文本块数据绑定到计数值。我需要做些什么才能让它发挥作用。谢谢!
class customVM : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChange(string PropertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(PropertyName));
}
}
private int _count;
public int Count
{
get { return _count; }
set {
_count = value;
OnPropertyChange(nameof(Count));
}
}
public async void methodAsync()
{
await method();
}
private Task method()
{
return Task.Run(() =>
{
for (int i = 0; i < 10; i++)
{
Task.Delay(1000).Wait();
//*************
Count = i;
//*************
}
});
}
}
答案 0 :(得分:2)
不需要将PropertyChanged
从另一个线程发送到UI线程,因为PropertyChanged
事件会自动编组到UI调度程序。
private Task method()
{
//The following code is okay. There is no need to marshal it explicitly
return Task.Run(() =>
{
for (int i = 0; i < 10; i++)
{
Task.Delay(1000).Wait();
//*************
Count = i;
//*************
}
});
}
正如MSDN article所说:
请注意,在WPF中,情况有所不同,代码如图5所示 即使Status属性是数据绑定到TextBlock也可以工作。这个 是因为WPF自动将PropertyChanged事件调度到 主线程,与所有其他XAML框架不同。在所有其他 框架,需要一个调度解决方案。
但是,仅适用于标量属性的更改通知(即PropertyChanged
事件)。集合更改通知(INotifyCollectionChanged.CollectionChanged
事件)不会以这种方式工作,必须手动在UI线程上引发它们。也就是说,当使用INotifyCollectionChanged
(例如使用ObservableCollection
)时,这些更改不会封送到UI线程。这意味着如果您从非UI线程修改集合,您将获得异常。我们在ViewModel类中,我们不使用Dispatcher来更新UI。所以我建议你使用David Rickard的方法:
public static class DispatchService
{
public static void Invoke(Action action)
{
Dispatcher dispatchObject = Application.Current.Dispatcher;
if (dispatchObject == null || dispatchObject.CheckAccess())
{
action();
}
else
{
dispatchObject.Invoke(action);
}
}
}
和
DispatchService.Invoke(() =>
{
this.MyCollection.Add("new value");
});
答案 1 :(得分:2)
跨线程标量属性绑定仅适用于WPF(也可能适用于Xamarin)。它不在其他MVVM平台上工作。
您的代码似乎是一种进度报告。适当的解决方案是IProgress<T>
Progress<T>
:
class customVM : INotifyPropertyChanged
{
private int _count;
public int Count
{
get { return _count; }
set {
_count = value;
OnPropertyChange(nameof(Count));
}
}
public async void methodAsync()
{
var progress = new Progress<int>(count => { Count = count; });
await Task.Run(() => method(progress));
}
private void method(IProgress<int> progress)
{
for (int i = 0; i < 10; i++)
{
Thread.Sleep(1000);
progress.Report(i);
}
}
}
Progress<T>
适用于所有UI平台,包括具有不同类型调度程序的平台,甚至包括WinForms等非MVVM平台。