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

时间:2018-12-10 14:51:38

标签: .net wpf data-binding dynamic-data reactiveui

在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获取器在内部创建列表的副本,这意味着列表中的更改不会反映在视图中。

我的第三次尝试是使用Bind方法创建一个ReadOnlyObservableCollection。 我不想在viewmodel中执行此操作,因为那样的话,我将不得不为每个viewmodel中的每个列表添加第二个list属性,这会使我的代码混乱,这违反了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 个答案:

答案 0 :(得分:1)

我认为这样的想法是,视图绑定到调度程序线程上的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的更多信息。