2016-12-15 448 views
1

我使用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

回答

1

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上執行更新。

相關問題