属性更改时运行长操作

时间:2017-05-29 16:05:49

标签: c# .net wpf async-await task-parallel-library

当我的属性引发PropertyChanged事件时,如何运行一些长操作? 例如:

class SomeClass : INotifyPropertyChanged
{
    public ObservableConllection<Item> Items { get; set; }
    public string Path
    {
         get => _path;
         if (_path != value) {
             _path = value;
             OnPropertyChanged(nameof(Path));
             // await Task.Run(()=> long operation, for example load some Items use "_path");
    }
}

属性不能异步,我认为它是“正常的”。但是我该怎么办? 我认为这种情况经常发生。

2 个答案:

答案 0 :(得分:1)

你应该阅读Stephen Cleary关于异步数据绑定属性的MSDN文章,他定义了一个名为NotifyTaskCompletion<T>的“任务观察者”类,它实现了INotifyPropertyChanged接口,并具有Result属性你可以绑定到:

异步编程:异步MVVM应用程序的模式:数据绑定: https://msdn.microsoft.com/en-us/magazine/dn605875.aspx

public class MainViewModel : INotifyPropertyChanged
{
    public string Path
    {
        get { return _path; }
        set
        {
            if (_path != value)
            {
                _path = value;
                OnPropertyChanged(nameof(Path));
                AsyncProperty = new NotifyTaskCompletion<int>(YourAsyncMethod());
            }
        }
    }

    public NotifyTaskCompletion<string> AsyncProperty { get; private set; }
}
<Label Content="{Binding AsyncProperty.Result}"/>

答案 1 :(得分:0)

您可以使用var key = "SOFTWARE\\Microsoft\\Expression\\Encoder\\4.0"; using (var registryKey = Registry.LocalMachine.OpenSubKey(key)) { if (registryKey == null) { using (var newKey = Registry.LocalMachine.CreateSubKey(key)) { CheckInstallKey(newKey); } } else { CheckInstallKey(registryKey); } } 而不使用Task.Run。根据具体情况,它可能运行也可能不运作,对此没有普遍的答案。

您可以创建这样的方法来设置值,这是一种更加可靠的方法。但是,如果您需要数据绑定,则无法使用:

await

如果您需要数据绑定并且想要使用public async Task SetPath(string value) { if (_path != value) { _path = value; OnPropertyChanged(nameof(Path)); await Task.Run(()=> ...); } ,那么通常最好的做法是使用定时器进行去抖动 - 您不希望在不受用户限制的情况下使用某些昂贵的操作,以便他可以冻结或崩溃应用程序。