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