AutoRefreshOnObservable работает только один раз. Зачем? - PullRequest
0 голосов
/ 11 апреля 2019

Я работаю над небольшой программой, в которой я оцениваю, является ли реактивный интерфейс подходящей основой для другого проекта. Пока все хорошо ... На данный момент я немного потерян в функции, связанной с DynamicData. Я пытаюсь выполнить команду в MainViewWindow каждый раз, когда поле со списком в ReactiveUserControl изменяется. Все мои модели расширяют ReactiveObject, а свойства настраиваются с помощью установщика RaiseAndSetIfChanged.

В моей ReactiveUserControl ViewModel я вызываю мою команду SaveImage из ReactiveUserControl ViewModel, как описано здесь: 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();
        }

При первом изменении поля со списком оно оценивается правильно. Я получаю «Ура». Но каждый раз после этого нет выхода. Если я снова вызову команду Watch Files, она снова будет работать один раз. Почему это происходит, и как я могу решить, чтобы распечатать каждый раз, когда файл изменил «Ура»? Я вижу, что ObservableCollection обнаруживает изменение, а также команда в ReactiveUserControl вызывается при изменении. Но метод WhenAnyFileChanged не возвращает измененный элемент после первого вызова. Надеюсь, понятно, чего я пытаюсь достичь, в чем проблема.

Обновление: я не знаю почему, но если я проверяю ChangeSet в Select (), я получаю TotalChanges 10 при инициализации, и это правильно. Тогда с моим первым рабочим изменением TotalChanges равно 0, но оценивается правильно. На моей следующей попытке изменить я все еще получаю 0 TotalChanges, но также нет правильной оценки в WhenAnyFileChanged (). Refreshes () равен 1 при каждом изменении.

Обновление 2: изменение AutoRefreshOnObservable () на AutoRefresh () приносит желаемую функциональность.

1 Ответ

0 голосов
/ 14 апреля 2019

Я скопировал исходный пример шины сообщений и написал модульный тест, чтобы увидеть, работает ли код так, как ожидалось. Я могу подтвердить, что проблема, которую вы видите, присутствует в примере. Следующий код срабатывает только один раз.

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 Dynamic Data, который похож на Merge Rx, но автоматически связывает наблюдаемые, когда элементы добавляются в базовый список, и отключает их, когда элементы удалены. Исправление:

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

Запуск одного и того же прохождения модульных тестов.

Код с модульным тестом доступен в этом списке

...