ReactiveUI:使用ReactiveCommand.CreateFromObservable()时,UI不会更新,直到命令完成

问题描述:

我使用ReactiveUI 7.0与WPF和.NET 4.5.2。ReactiveUI:使用ReactiveCommand.CreateFromObservable()时,UI不会更新,直到命令完成

我试图从Observable创建一个ReactiveCommand。代码确实工作,但是,直到命令完成后才会更新UI。我有一个进度条和一个我想在命令运行时更新的进度窗口。另外,当ReactiveCommand正在执行时,UI是无响应的(我无法点击取消按钮或其他任何事情)。我希望这是我忽略的,对于比我更聪明的人来说是显而易见的。或者,也许我只是做错了。

感谢您的期待。

下面是相关代码:

我的视图模型声明:

public ReactiveCommand<Unit, string> PerformSelectedOperationCommand { get; set; } 

private StringBuilder sb; 

在我的视图模型构造:

PerformSelectedOperationCommand = ReactiveCommand.CreateFromObservable(PerformOperationObservable, 
      this.WhenAnyValue(x => x.SelectedPath, x => x.TotalFilesSelected, 
       (x, y) => x != null && y > 0)); 

    // listen to the messages and append to output 
    PerformSelectedOperationCommand.Subscribe(s => 
    { 
     sb.AppendLine(s); 
     ProgressWindowOutput = sb.ToString(); 
    }); 

这里是包含在我的视图模型运行于可观测当点击Go按钮时(注意它正在修改我的ViewModel的属性):

private IObservable<string> PerformOperationObservable() 
    { 
     sb.Clear(); 
     return Observable.Create<string>((o) => 
     { 
      using (cts = new CancellationTokenSource()) 
      { 
       // this creates a copy of the file list which will keep us safe 
       // if the user is clicking around on the UI and changing the list. 
       var selectedFiles = FileList.Where(x => x.IsChecked).ToArray(); 
       int total = selectedFiles.Length; 
       int count = 0; 
       foreach (var file in selectedFiles) 
       { 
        ProgressBarMessage = $"Processing {count + 1} of {total}"; 
        o.OnNext($"Processing file {file.Name}"); 
        SelectedFileOperation.PerformOperation(file.FullPath); 
        count++; 
        PercentComplete = (int)(((double)count/total) * 100); 
        if (cts.IsCancellationRequested) 
        { 
         PercentComplete = 0; 
         ProgressBarMessage = string.Empty; 
         break; 
        } 
       } 
       ProgressBarMessage = string.Empty; 
      } 
      o.OnCompleted(); 
      return Disposable.Empty; 
     }); 
    } 
+0

UI冻结的事实表明您在调度程序(UI)线程上执行繁重的工作。读这应该帮助你包围你的头围绕这个主题:http://www.introtorx.com/content/v1.0.10621.0/15_SchedulingAndThreading.html – pmbanka

Observable本质上是单线程的,您需要指定从哪里开始工作。你能做到这一点,我相信:

PerformSelectedOperationCommand = ReactiveCommand.CreateFromObservable(PerformOperationObservable.SubscribeOn(RxApp.TaskPoolScheduler), // Move subscription to task pool 
     this.WhenAnyValue(x => x.SelectedPath, x => x.TotalFilesSelected, 
      (x, y) => x != null && y > 0)); 

// listen to the messages and append to output 
PerformSelectedOperationCommand 
    .ObserveOnDispather() // Return to UI thread 
    .Subscribe(s => 
    { 
     sb.AppendLine(s); 
     ProgressWindowOutput = sb.ToString(); 
    }); 

您明确订阅观察到的任务池,移动UI线程的工作。在使用输出之前,您将返回到UI线程以便能够在UI上执行更新。