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

7
在 ReactiveUI 9 中,ReactiveList 已被弃用,使用 DynamicData 代替 (博客文章)。我目前正在尝试更新我的代码以使用 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);

这样做完全没问题,但是有点啰嗦。我可以为此创建一个扩展方法,但也许有更好/内置的方法来使用DynamicData进行WPF列表绑定吗?
1个回答

10

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

您可以在 这里 阅读更多有关此内容的信息。


1
如果您不进行多线程相关操作,也不执行与旧的ReactiveDerivedList相关的操作,则可以使用ObservableCollectionExtended。 - Glenn Watson
4
好吧,我想这回答了我的问题。现在需要在使用ReactiveList的每个地方添加一个额外的列表有点烦人。这肯定不会使代码更易读。我想我会编写一个扩展方法来隐藏这个样板文件。 - Wouter

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接