Использование IObservable (Rx) в качестве замены INotifyCollectionChanged для MVVM?

Я изучал возможность использования Rx в среде MVVM. Идея состоит в том, чтобы использовать «живые» запросы LINQ к наборам данных в памяти для проецирования данных в модели представления для привязки.

Ранее это было возможно с использованием INotifyPropertyChanged / INotifyCollectionChanged и библиотеки с открытым исходным кодом под названием CLINQ . Потенциал с Rx и IObservable заключается в переходе к гораздо более декларативной модели ViewModel с использованием классов Subject для передачи измененных событий из исходной модели во View. На последнем этапе потребуется преобразование из IObservable в обычные интерфейсы привязки данных.

Проблема в том, что Rx, похоже, не поддерживает уведомление о том, что объект был удален из потока. Пример ниже.
Код показывает POCO, который использует класс BehaviorSubject для состояния поля. Код переходит к созданию коллекции этих сущностей и использованию Concat для объединения потоков фильтров. Это означает, что о любых изменениях POCO сообщается в один поток.

Фильтр для этого потока настроен на фильтрацию для рейтинга == 0. Подписка просто выводит результат в окно отладки при возникновении четности.

Рейтинг настроек = 0 для любого элемента вызовет событие. Но установка рейтинга обратно на 5 не приведет к появлению каких-либо событий.

В случае CLINQ вывод запроса будет поддерживать INotifyCollectionChanged - так что элементы, добавленные и удаленные из результата запроса, будут вызывать правильное событие, чтобы указать, что результат запроса имеет изменено (элемент добавлен или удален).

Единственный способ, которым я могу решить эту проблему, - это настроить два потока с противоположными (двойными) запросами. Элемент, добавленный в противоположный поток, подразумевает удаление из набора результатов. В противном случае я мог бы просто использовать FromEvent и не делать какие-либо модели сущностей наблюдаемыми, что делает Rx больше просто агрегатором событий. Есть указатели?

using System;
using System.ComponentModel;
using System.Linq;
using System.Collections.Generic;

namespace RxTest
{

    public class TestEntity : Subject, INotifyPropertyChanged
    {
        public IObservable FileObservable { get; set; }
        public IObservable RatingObservable { get; set; }

        public string File
        {
            get { return FileObservable.First(); }
            set { (FileObservable as IObserver).OnNext(value); }
        }

        public int Rating
        {
            get { return RatingObservable.First(); }
            set { (RatingObservable as IObserver).OnNext(value); }
        }

        public event PropertyChangedEventHandler PropertyChanged;

        public TestEntity()
        {
            this.FileObservable = new BehaviorSubject(string.Empty);
            this.RatingObservable = new BehaviorSubject(0);
            this.FileObservable.Subscribe(f => { OnNotifyPropertyChanged("File"); });
            this.RatingObservable.Subscribe(f => { OnNotifyPropertyChanged("Rating"); });
        }

        private void OnNotifyPropertyChanged(string property)
        {
            if (PropertyChanged != null) PropertyChanged(this, new PropertyChangedEventArgs(property));
            // update the class Observable
            OnNext(this);
        }

    }

    public class TestModel
    {
        private List collection { get; set; }
        private IDisposable sub;

        public TestModel()
        {
            this.collection = new List() {
            new TestEntity() { File = "MySong.mp3", Rating = 5 },
            new TestEntity() { File = "Heart.mp3", Rating = 5 },
            new TestEntity() { File = "KarmaPolice.mp3", Rating = 5 }};

            var observableCollection = Observable.Concat(this.collection.Cast>());
            var filteredCollection = from entity in observableCollection
                                     where entity.Rating==0
                                     select entity;
            this.sub = filteredCollection.Subscribe(entity =>
                {
                    System.Diagnostics.Debug.WriteLine("Added :" + entity.File);
                }
            );
            this.collection[0].Rating = 0;
            this.collection[0].Rating = 5;
        }
    };
}

7
задан Joe Wood 18 January 2011 в 14:27
поделиться