繁体   English   中英

如何实现异步INotifyPropertyChanged

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM