ReactiveUI 9:将列表绑定到 WPF 视图

ReactiveUI 9: binding lists to a WPF view

在 ReactiveUI 9 中,ReactiveList 已被弃用,取而代之的是 DynamicData (Blog post)。我目前正在尝试更新我的代码以使用 SourceList。我能够让 ViewModel 工作,但似乎在 WPF 中使用 SourceList 作为绑定数据源并不那么容易。

我的第一次尝试是创建绑定,就像在以前版本的 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 getter 在内部创建了列表的副本,这意味着列表中的更改不会反映在视图中。

我的第三次尝试是使用 Bind 方法创建一个 ReadOnlyObservableCollection。 我不想在视图模型中执行此操作,因为那样我就必须为每个视图模型中的每个列表添加第二个列表 属性,这会扰乱我的代码,违反了 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);

这工作正常,但非常冗长。我可以为此创建一个扩展方法,但也许有一种 better/built-in 方法来使用 DynamicData 进行 WPF 列表绑定?

我认为这个想法是视图绑定到调度程序线程上的 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);

您可以阅读更多相关信息 here