我正在将 ReactiveUI 7.0 与 WPF 和 .NET 4.5.2 一起使用。
我正在尝试从 Observable 创建 ReactiveCommand。该代码确实有效,但是,在命令完成之前 UI 不会更新。我有一个进度条和一个进度窗口,我想在命令运行时更新它们。此外,在执行 ReactiveCommand 时,UI 无响应(我无法单击取消按钮或其他任何与此相关的按钮)。我希望这是我所忽视的事情,并且对于比我聪明的人来说是显而易见的。或者也许我只是做错了。
感谢您的浏览。
相关代码如下:
我的 ViewModel 声明:
public ReactiveCommand<Unit, string> PerformSelectedOperationCommand { get; set; }
private StringBuilder sb;
在我的 ViewModel 构造函数中:
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();
});
这是我的 ViewModel 中包含的 Observable,它在单击 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 上进行更新。