AutoRefreshOnObservable仅工作一次。为什么?

时间:2019-04-11 11:13:59

标签: wpf dynamic-data reactiveui

我正在开发一个小型程序,其中我在评估响应式ui是否是另一个项目的正确框架。到目前为止一切顺利...目前,我有点不了解DynamicData相关功能。每当更改ReactiveUserControl中的组合框时,我都试图在MainViewWindow中执行命令。我所有的模型都在扩展ReactiveObject,并且使用RaiseAndSetIfChanged设置器设置属性。

在我的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; }

初始化集合,文件是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”后,如何解决该问题才能打印?我可以看到,ObservableCollection会检测到更改,并且还会在更改时调用ReactiveUserControl中的Command。但是,第一次调用后,WhenAnyFileChanged方法不会返回更改后的元素。 希望我能达到的目标是可以理解的,这是什么问题。

更新:我不知道为什么,但是如果我在Select()中检查ChangeSet,则在初始化时会得到TotalChanges 10,这是正确的。然后在我的第一个工作更改中,TotalChanges为0,但评估正确。在下一次尝试更改时,我仍然得到0 TotalChanges,但是在WhileAnyFileChanged()中也没有正确的评估。 每次更改时Refreshes()均为1。

更新2:将AutoRefreshOnObservable()更改为AutoRefresh()可带来所需的功能。

1 个答案:

答案 0 :(得分:0)

我复制了原始消息总线示例,并编写了一个单元测试,以查看代码是否按预期运行。我可以确认示例中存在您所看到的问题。以下代码仅触发一次。

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();
}

我不确定为什么会失败,但是最好的解决方法是利用Dynamic Data的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