ReactiveUI 9: привязка списков к представлению WPF - PullRequest
0 голосов
/ 10 декабря 2018

В ReactiveUI 9 ReactiveList устарело в пользу DynamicData ( Пост блога ).В настоящее время я пытаюсь обновить свой код для использования SourceList.Мне удалось заставить ViewModel работать, однако кажется, что использование SourceList в качестве источника данных привязки в WPF не так просто.

Моя первая попытка была создать привязку, как это было в предыдущих версияхReactiveUI:

this.OneWayBind(ViewModel, vm => vm.MyList, v => v.MyListView.ItemsSource);

Это не работает, поскольку SourceList не перечисляемо (невозможно преобразовать DynamicData.ISourceList в System.Collections.IEnumerable)

Моя вторая попытка былаиспользуйте свойство Items списка.

this.OneWayBind(ViewModel, vm => vm.MyList.Items, v => v.MyListView.ItemsSource);

Это не работает, потому что получатель Items внутренне создает копию списка, что означает, что изменения в списке не будут отражены впредставление.

Моя третья попытка заключалась в использовании метода Bind для создания ReadOnlyObservableCollection.Я не хочу делать это в viewmodel, потому что тогда мне нужно будет добавить второе свойство list для каждого списка в каждой viewmodel, что загромождает мой код, нарушая принцип DRY.Кроме того, тип списка для привязки зависит от используемой структуры представления.(например: WinForms вместо этого использует BindingList)

Также может измениться модель просмотра моего представления, что означает, что результирующая привязка и список должны быть очищены и заменены, когда установлена ​​новая модель представления.Это дает мне следующий фрагмент:

this.WhenAnyValue(v => v.ViewModel.VisibleInputs)
    .Select(l =>
    {
        var disposer = l.Connect().Bind(out var list).Subscribe();
        return (List: list, Disposer: disposer);
    })
    .PairWithPreviousValue()
    .Do(p => p.OldValue.Disposer?.Dispose()) // Cleanup the previous list binding
    .Select(p => p.NewValue.List)
    .BindTo(this, v => v.InputsList.ItemsSource);

Это прекрасно работает, но довольно многословно.Я мог бы создать метод расширения для этого, но, может быть, есть лучший / встроенный способ связывания списка WPF с DynamicData?

1 Ответ

0 голосов
/ 10 декабря 2018

Я думаю, что идея заключается в том, что представление связывается с IObservableCollection<T> в потоке диспетчера и что SourceList<T> снабжает его объектами, которые создает поток, например:

public class MainViewModel : ReactiveObject
{
    private SourceList<int> _myList { get; } = new SourceList<int>();
    private readonly IObservableCollection<int> _targetCollection = new ObservableCollectionExtended<int>();

    public MainViewModel()
    {
        Task.Run(()=> 
        {
            for (int i = 0; i < 100; ++i)
            {
                _myList.Add(i);
                System.Threading.Thread.Sleep(500);
            }
        });
        _myList.Connect()
            .ObserveOnDispatcher()
            .Bind(_targetCollection)
            .Subscribe();            
    }

    public IObservableCollection<int> TargetCollection => _targetCollection;
}

Просмотр:

this.OneWayBind(ViewModel, vm => vm.TargetCollection, v => v.MyListView.ItemsSource);

Подробнее об этом можно прочитать здесь .

...