[英]How to implement async INotifyPropertyChanged
我有一个类,其属性绑定到我的视图。 为了使我的视图保持最新,我实现了INotifyPropertyChanged并在每次某些属性更改时引发事件。
现在我得到了一些重要的函数来冻结我的应用程序 我想把它们放到后台任务中。
第一:这是我目前的做法
(例如点击按钮)
private async void HeavyFunc()
{
foreach (var stuff)
{
count += await Task.Run(() => stuff.Fetch());
}
if (count == 0)
//...
}
东西类
public async Task<int> Fetch()
{
//network stuff
RaisePropertyChanged("MyProperty");
}
public async void RaisePropertyChanged(string pChangedProperty)
{
await Application.Current.Dispatcher.BeginInvoke(
System.Windows.Threading.DispatcherPriority.Normal,
new ThreadStart(() =>
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(pChangedProperty);
}
);
}
上面的代码给出了一个异常(“DependencySource”必须在同一个线程中创建,如“DependencyObject”)。
AFAIK,你通常需要创建一个新线程并运行它(等待它)。 'goit Task.Run(...);'应该做这个工作。
由于PropertyChanged事件直接影响UI,因此在UI线程中调用它似乎是一个很好的决定。 这就是我调用Dispatcher.BeginInvoke的原因。
我不明白:上面的例外是由不同的线程负责数据引起的。 但我明确地在我的UI线程上调用该事件,该对象也应该由UI线程创建。 那么为什么我会得到例外?
我的主要问题是:如何实现INotifyPropertyChanged接口的事件通常是为了避免或处理上面的大多数异步编程问题? 构建函数时应该考虑什么?
现在我得到了一些重要的函数来冻结我的应用程序
如果你真的在做异步“网络东西”,那么它不应该冻结应用程序。
我的主要问题是:如何实现INotifyPropertyChanged接口的事件通常是为了避免或处理上面的大多数异步编程问题?
我更喜欢的方法是在提升代码时不处理这个问题。 相反,构建其余代码以使其尊重UI层。
换句话说,将“服务”(或“业务逻辑”)代码从“UI”代码中划分出来,使其工作方式如下:
// In StuffService class:
public async Task<Result> FetchAsync()
{
//network stuff
return result;
}
// In StuffViewModel class:
public async void ButtonClicked()
{
foreach (var stuff)
{
var result = await Task.Run(() => _stuffService.FetchAsync());
MyProperty = result.MyProperty;
count += result.Count;
}
if (count == 0)
//...
}
public Property MyProperty
{
get { return _myProperty; }
set
{
_myProperty = value;
RaisePropertyChanged();
}
}
private void RaisePropertyChanged([CallerMemberName] string pChangedProperty = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(pChangedProperty));
}
这样,就没有手动跳线,所有属性都有标准的ViewModel实现,代码更简单,更易于维护等。
我确实离开了对Task.Run
的调用,尽管如果您的网络调用是真正的异步,这应该是多余的。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.