AutoRefreshOnObservable 只工作一次。为什么?
AutoRefreshOnObservable only works once. Why?
我正在开发一个小程序,我正在评估响应式 ui 是否是另一个项目的正确框架。到目前为止这么好......目前我有点迷失在 DynamicData 相关功能中。每次更改 ReactiveUserControl 中的组合框时,我都试图在 MainViewWindow 中执行命令。我所有的模型都在扩展 ReactiveObject 并且属性是用 RaiseAndSetIfChanged setter.
设置的
在我的 ReactiveUserControl ViewModel 中,我从 ReactiveUserControl ViewModel 调用我的命令 SaveImage,如下所述:
https://reactiveui.net/docs/handbook/message-bus/#ways-to-avoid-using-messagebus
定义 ObservableCollection
public ObservableCollection<FileViewModel> VisibleFiles { get; protected set; }
初始化集合,Files是一个SourceList
WatchFiles = ReactiveCommand.Create(() =>
{
VisibleFiles = new ObservableCollection<FilesViewModel>(Files.Items);
VisibleFiles.ToObservableChangeSet().AutoRefreshOnObservable(doc => doc.SaveImage).Select(_ => WhenAnyFileChanged()).Switch().Subscribe<FilesViewModel>(x => {
Console.WriteLine("HOORAY");
});
});
private IObservable<FilesViewModel> WhenAnyFileChanged()
{
return VisibleFiles.Select(x => x.SaveFile.Select(_ => x )).Merge();
}
第一次更改组合框时,它的评估是正确的。我得到 "Hooray"。但是之后每次都没有输出。如果我再次调用 Watch Files 命令,它会再次工作一次。
为什么会发生这种情况,我该如何解决每次文件更改 "Hooray" 时打印的问题?我可以看到,ObservableCollection 检测到更改,并且 ReactiveUserControl 中的命令也会在更改时被调用。但是 WhenAnyFileChanged 方法在第一次调用后不会 return 更改的元素。
希望我正在努力实现的目标是可以理解的,问题是什么。
更新:我不知道为什么,但是如果我检查 Select() 中的 ChangeSet,我会在初始化时得到 TotalChanges 10,这是正确的。然后,我的第一个工作更改 TotalChanges 为 0,但评估正确。在我下次尝试更改时,我仍然得到 0 TotalChanges,但在 WhenAnyFileChanged() 中也没有正确的评估。
每次更改时 Refreshes() 为 1。
更新 2:将 AutoRefreshOnObservable() 更改为 AutoRefresh() 带来了所需的功能。
我复制了原始消息总线示例并编写了单元测试以查看代码是否按预期运行。我可以确认您看到的问题存在于示例中。以下代码只触发一次。
public MainViewModel()
{
OpenDocuments = new ObservableCollection<DocumentViewModel>();
OpenDocuments
.ToObservableChangeSet()
.AutoRefreshOnObservable(document => document.Close)
.Select(_ => WhenAnyDocumentClosed())
.Switch()
.Subscribe(x => OpenDocuments.Remove(x), ex=>{},()=>{});
}
IObservable<DocumentViewModel> WhenAnyDocumentClosed()
{
return OpenDocuments
.Select(x => x.Close.Select(_ => x))
.Merge();
}
这是证明这一点的测试。第二次尝试删除失败。
[Fact]
public void MyTest()
{
//I added an id field to help with diagnostics / testing
_mainViewModel.OpenDocuments.Count.Should().Be(4);
_mainViewModel.OpenDocuments.Any(dvm => dvm.Id == "1").Should().BeTrue();
_mainViewModel.OpenDocuments[0].Close.Execute().Subscribe();
_mainViewModel.OpenDocuments.Count.Should().Be(3);
_mainViewModel.OpenDocuments.Any(dvm => dvm.Id == "1").Should().BeFalse();
_mainViewModel.OpenDocuments[0].Close.Execute().Subscribe();
_mainViewModel.OpenDocuments.Count.Should().Be(2);
_mainViewModel.OpenDocuments.Any(dvm => dvm.Id == "2").Should().BeFalse();
}
我不确定为什么会失败,但最佳解决方案是使用动态数据的 MergeMany
运算符,它类似于 Rx 的 Merge
但在将项目添加到底层列表并在删除项目时取消它们。修复是:
public class MainViewModel : ReactiveObject
{
public ObservableCollection<DocumentViewModel> OpenDocuments { get;}
public MainViewModel()
{
OpenDocuments = new ObservableCollection<DocumentViewModel>();
OpenDocuments
.ToObservableChangeSet()
.MergeMany(x => x.Close.Select(_ => x))
.Subscribe(x => OpenDocuments.Remove(x));
}
}
运行 相同的单元测试通过。
带有单元测试的代码可用in this gist
我正在开发一个小程序,我正在评估响应式 ui 是否是另一个项目的正确框架。到目前为止这么好......目前我有点迷失在 DynamicData 相关功能中。每次更改 ReactiveUserControl 中的组合框时,我都试图在 MainViewWindow 中执行命令。我所有的模型都在扩展 ReactiveObject 并且属性是用 RaiseAndSetIfChanged setter.
设置的在我的 ReactiveUserControl ViewModel 中,我从 ReactiveUserControl ViewModel 调用我的命令 SaveImage,如下所述: https://reactiveui.net/docs/handbook/message-bus/#ways-to-avoid-using-messagebus
定义 ObservableCollection
public ObservableCollection<FileViewModel> VisibleFiles { get; protected set; }
初始化集合,Files是一个SourceList
WatchFiles = ReactiveCommand.Create(() =>
{
VisibleFiles = new ObservableCollection<FilesViewModel>(Files.Items);
VisibleFiles.ToObservableChangeSet().AutoRefreshOnObservable(doc => doc.SaveImage).Select(_ => WhenAnyFileChanged()).Switch().Subscribe<FilesViewModel>(x => {
Console.WriteLine("HOORAY");
});
});
private IObservable<FilesViewModel> WhenAnyFileChanged()
{
return VisibleFiles.Select(x => x.SaveFile.Select(_ => x )).Merge();
}
第一次更改组合框时,它的评估是正确的。我得到 "Hooray"。但是之后每次都没有输出。如果我再次调用 Watch Files 命令,它会再次工作一次。 为什么会发生这种情况,我该如何解决每次文件更改 "Hooray" 时打印的问题?我可以看到,ObservableCollection 检测到更改,并且 ReactiveUserControl 中的命令也会在更改时被调用。但是 WhenAnyFileChanged 方法在第一次调用后不会 return 更改的元素。 希望我正在努力实现的目标是可以理解的,问题是什么。
更新:我不知道为什么,但是如果我检查 Select() 中的 ChangeSet,我会在初始化时得到 TotalChanges 10,这是正确的。然后,我的第一个工作更改 TotalChanges 为 0,但评估正确。在我下次尝试更改时,我仍然得到 0 TotalChanges,但在 WhenAnyFileChanged() 中也没有正确的评估。 每次更改时 Refreshes() 为 1。
更新 2:将 AutoRefreshOnObservable() 更改为 AutoRefresh() 带来了所需的功能。
我复制了原始消息总线示例并编写了单元测试以查看代码是否按预期运行。我可以确认您看到的问题存在于示例中。以下代码只触发一次。
public MainViewModel()
{
OpenDocuments = new ObservableCollection<DocumentViewModel>();
OpenDocuments
.ToObservableChangeSet()
.AutoRefreshOnObservable(document => document.Close)
.Select(_ => WhenAnyDocumentClosed())
.Switch()
.Subscribe(x => OpenDocuments.Remove(x), ex=>{},()=>{});
}
IObservable<DocumentViewModel> WhenAnyDocumentClosed()
{
return OpenDocuments
.Select(x => x.Close.Select(_ => x))
.Merge();
}
这是证明这一点的测试。第二次尝试删除失败。
[Fact]
public void MyTest()
{
//I added an id field to help with diagnostics / testing
_mainViewModel.OpenDocuments.Count.Should().Be(4);
_mainViewModel.OpenDocuments.Any(dvm => dvm.Id == "1").Should().BeTrue();
_mainViewModel.OpenDocuments[0].Close.Execute().Subscribe();
_mainViewModel.OpenDocuments.Count.Should().Be(3);
_mainViewModel.OpenDocuments.Any(dvm => dvm.Id == "1").Should().BeFalse();
_mainViewModel.OpenDocuments[0].Close.Execute().Subscribe();
_mainViewModel.OpenDocuments.Count.Should().Be(2);
_mainViewModel.OpenDocuments.Any(dvm => dvm.Id == "2").Should().BeFalse();
}
我不确定为什么会失败,但最佳解决方案是使用动态数据的 MergeMany
运算符,它类似于 Rx 的 Merge
但在将项目添加到底层列表并在删除项目时取消它们。修复是:
public class MainViewModel : ReactiveObject
{
public ObservableCollection<DocumentViewModel> OpenDocuments { get;}
public MainViewModel()
{
OpenDocuments = new ObservableCollection<DocumentViewModel>();
OpenDocuments
.ToObservableChangeSet()
.MergeMany(x => x.Close.Select(_ => x))
.Subscribe(x => OpenDocuments.Remove(x));
}
}
运行 相同的单元测试通过。
带有单元测试的代码可用in this gist