Наблюдение за командами в другой ViewModel - PullRequest
2 голосов
/ 17 июня 2020

Я не знаю, как назвать этот вопрос, поскольку я не уверен, что не так, но у меня проблемы с наблюдением за командами в другой модели просмотра.

У меня есть BoxPageViewModel, который содержит SourceCache<BoxViewModel> «Коробки» и SourceCache<ItemViewModel> «Элементы». Мне нужна функциональность для добавления ItemViewModel в BoxViewModel, а затем его следует удалить из 'Items'.

Мой план состоит в том, чтобы добавить в BoxViewModel команду Add, которая добавляет элемент в SourceList в BoxViewModel . Модель BoxPageViewModel "слушает", когда какой-либо из ее блоков вызывает "Добавить", а затем удаляет самый новый элемент этого блока из "Items"

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

Моя проблема в том, что код для удаления элемента из ItemsSource вызывается только до того, как ObservableAsPropertyHelper 'IsFull' в BoxViewModel установлен для первого время, и я понятия не имею, почему. На данный момент IsFull должно быть истинным, если Box содержит 2 или более элементов. Когда я добавляю первый элемент в Box, он удаляется из элементов в BoxPageViewModel. Но когда я добавляю второй элемент, код для удаления элемента из Items никогда не вызывается.

Если я удалю «IsFull», он будет работать нормально, но мне действительно нужен способ узнать, когда все ящики «заполнены» или «закончены» каким-либо образом.

Я пробовал использовать .ToObservableChangeSet().AutoRefreshOnObservable(x => x.Add) вместо .ToObservableChangeSet().AutoRefresh(), но это не имеет значения. Я немного растерялся, так как не совсем понимаю, как это работает. Я действительно хотел бы получить объяснение того, почему код ведет себя именно так.

Бонусный вопрос: я также не могу получить для свойства «Done» BoxPageViewModel значение true, хотя я проверил в тестовом методе _boxes.Select(b => b.All(x => x.IsFull)) верно. Что-то не так с тем, как я определил это свойство?

public class BoxViewModel : ReactiveObject
    {
        readonly ObservableAsPropertyHelper<bool> isFull;
        public bool IsFull => isFull.Value;

        public SourceList<Item> Items = new SourceList<Item>();

        public ReactiveCommand<int, Unit> Add { get; }

        public BoxViewModel()
        {
            Add = ReactiveCommand.Create<int>(AddToBox);

            Items.Connect()
                .ToCollection()
                .Select(c => c.Count >= 2)
                .ToProperty(this, x => x.IsFull, out isFull);
        }

        private void AddToBox(int id)
        {
            // Adding a new item while testing.
            Items.Add(new Item { Id = id });
        }
    }

В BoxPageViewModel я пытаюсь наблюдать, когда вызывается команда AddToBox, а затем удаляю элемент из его Items SourceCache.

public class BoxPageViewModel : ReactiveObject, IRoutableViewModel
    {
        private SourceCache<Item, int> ItemsSource = new SourceCache<Item, int>(x => x.Id);

        private SourceCache<BoxViewModel, int> BoxSource = new SourceCache<BoxViewModel, int>(x => x.Id);
        private ReadOnlyObservableCollection<BoxViewModel> _boxes;
        public ReadOnlyObservableCollection<BoxViewModel> Boxes => _boxes;

        private ReadOnlyObservableCollection<Item> _items;
        public ReadOnlyObservableCollection<Item> Items => _items;

        readonly ObservableAsPropertyHelper<bool> done;
        public bool Done => done.Value;

        public BoxPageViewModel()
        {
            var box1 = new BoxViewModel { Id = 1 };
            var box2 = new BoxViewModel { Id = 2 };

            BoxSource.AddOrUpdate(box1);
            BoxSource.AddOrUpdate(box2);

            // I have left out the part where my items are created
            ItemsSource.AddOrUpdate(items);

            ItemsSource.Connect()
                .ObserveOn(RxApp.MainThreadScheduler)
                .Bind(out _items)
                .Subscribe();

            BoxSource.Connect()
                .ObserveOn(RxApp.MainThreadScheduler)
                .Bind(out _boxes)
                .Subscribe();

            _boxes.ToObservableChangeSet()
                .ToCollection()
                .Select(b => b.All(x => x.IsFull))
                .ToProperty(this, x => x.Done, out done);

            _boxes
                .ToObservableChangeSet()
                .AutoRefresh()
                .Select(_ => WhenAnyBoxAdded())
                .Switch()   
                .Subscribe(box =>
                {
                    var latestItem = box.Items.Items.Last();
                    ItemsSource.Remove(latestItem.Id);
                });
        }

        IObservable<BoxViewModel> WhenAnyBoxAdded()
        {
            return _boxes
                .Select(x => x.Add.Select(_ => x))
                .Merge();
        }
}

1 Ответ

0 голосов
/ 22 июня 2020

Если вы решили использовать MessageCenter. Класс Xamarin.Forms MessagingCenter реализует шаблон publi sh -subscribe, позволяя взаимодействовать на основе сообщений между компонентами, которые неудобно связывать по ссылкам на объекты и типы. Этот механизм позволяет издателям и подписчикам обмениваться данными, не ссылаясь друг на друга, что помогает уменьшить зависимости между ними.

Во-первых, подписание (этот код должен быть выполнен раньше):

Xamarin.Forms.MessagingCenter.Subscribe<object>(this, "key", async message =>
{                
   //your code here.
});

И отправив сообщение:

Xamarin.Forms.MessagingCenter.Send<object>(new object(), "key");
...