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

Wou*_*ter 4 .net data-binding wpf dynamic-data reactiveui

在 ReactiveUI 9 中,ReactiveList已弃用 DynamicData(博客文章)。我目前正在尝试更新我的代码以使用SourceList. 我能够让 ViewModel 工作,但是SourceList在 WPF 中用作绑定数据源似乎并不容易。

我的第一次尝试是创建绑定,就像在以前版本的 ReactiveUI 中所做的那样:

this.OneWayBind(ViewModel, vm => vm.MyList, v => v.MyListView.ItemsSource);
Run Code Online (Sandbox Code Playgroud)

这不起作用,因为SourceList不可枚举(无法将 DynamicData.ISourceList 转换为 System.Collections.IEnumerable)

我的第二次尝试是使用Items列表的属性。

this.OneWayBind(ViewModel, vm => vm.MyList.Items, v => v.MyListView.ItemsSource);
Run Code Online (Sandbox Code Playgroud)

这不起作用,因为Itemsgetter 在内部创建了列表的副本,这意味着列表中的更改不会反映在视图中。

我的第三次尝试是使用该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);
Run Code Online (Sandbox Code Playgroud)

这工作正常,但它非常冗长。我可以为此创建一个扩展方法,但也许有更好的/内置的方法来使用 DynamicData 进行 WPF 列表绑定?

mm8*_*mm8 7

我认为这个想法是视图绑定到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;
}
Run Code Online (Sandbox Code Playgroud)

看法:

this.OneWayBind(ViewModel, vm => vm.TargetCollection, v => v.MyListView.ItemsSource);
Run Code Online (Sandbox Code Playgroud)

您可以在此处阅读更多相关信息。

  • 好吧,我想这回答了我的问题。有点烦人的是,现在需要在使用 ReactiveList 的任何地方添加一个额外的列表。那绝对不会使代码更具可读性。我想我会写一个扩展方法来隐藏这个样板。 (3认同)