【问题标题】:WPF MVVM async worker methods with cancellation/overlapping call handling具有取消/重叠调用处理的 WPF MVVM 异步工作方法
【发布时间】:2016-09-23 15:29:53
【问题描述】:

我有一个从数据库加载数据的详细视图(用于列表选择),我不想通过将数据库逻辑从 UI 线程移开来避免任何阻塞。

问题:

  • 使其异步(简单的部分,在完成后调度更新 UI 部分上的 viewmodel 属性的逻辑)
  • 当用户(例如,按住 Down-Key)在后台线程完成最后一个条目之前加载新条目时进行处理
    • 在这种情况下,之前的加载方法应该是可取消的(例如 CanellationToken)
    • 为旧选择启动的调用结果必须被丢弃并且不会到达 UI,尤其是因为如果调用在稍后启动的加载操作之后完成,这可能会覆盖最新数据

如何使用 WPF 做到这一点?如果没有内置方法,我的想法是为此创建一个类并将其用于视图模型中的此类加载方法。例如。想到的两个变种的伪代码

    public class ViewModelBackgroundLoader<TInput, TResult>
    {
        public ViewModelBackgroundLoader(Func<TInput, CancellationToken, TResult> loadFunc, Action<TResult> uiContinuation)
        {
        }
        public void Load(TInput input)
        {
            // set cancellation for previous loadFunc
            // async await loadAction on threadpool thread
            // If not cancelled... 
            //   uiContinuation() on UI thread
        }
    }

    public class ViewModelBackgroundLoadedProperty<TInput, TResult> : INotifyPropertyChanged
    {
        public ViewModelBackgroundLoadedProperty(Func<TInput, CancellationToken, TResult> loadFunc)
        {
        }
        public TInput Input
        {
            set
            {
                // set cancellation for running loadFunc
                // async await loadAction on threadpool thread
                // If not cancelled... 
                //   Update Result property and fire propertychanged (in UI thread)
            }
        }
        public TResult Result { get; }
    }

【问题讨论】:

    标签: .net wpf asynchronous backgroundworker


    【解决方案1】:

    如果您使用我编写的名为 NotifyTask&lt;T&gt; 的帮助器类,这非常简单:

    public class ViewModel<TInput, TResult>
    {
      private CancellationTokenSource _cts;
    
      public NotifyTask<TResult> Operation { get; private set; }
    
      public void Load(TInput input)
      {
        if (_cts != null)
          _cts.Cancel();
        _cts = new CancellationTokenSource();
        Operation = NotifyTask.Create(loadFunc(input, _cts.Token));
      }
    }
    

    可以将数据绑定到Operation.Result(还有其他可绑定数据的属性可以轻松显示/隐藏加载指示器等)。

    CancellationTokenSource 的事情就像你描述的那样,取消之前的操作(如果有的话)。无需明确检查和避免旧操作​​的 UI 更新,因为 Operation 总是在新操作开始时被覆盖(因此永远不会显示旧数据 - 即使没有取消,它也会被忽略)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-11-19
      • 2019-08-04
      • 2017-12-16
      • 2016-04-07
      • 2019-03-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多