ReactiveUI MVVM框架(1)-Collections

ReactiveUI MVVM框架(1)-Collections

ReactiveUI使用动态数据(DynamicData)用于集合的操作。

当对动态数据集合进行更改时,会产生更改通知,通知表示为ChangeSet,里面包含了更改信息,多个更改通知为IObservable<ChangeSet>。动态数据提供了两种特定的集合,分别是SourceCache<TObject, TKey>SourceList<T>。第一个为带key的字典式,也就是不能重复,第二个为集合式。如何要将这两种集合转换为IObservable<ChangeSet>,可以使用Connect方法。

需要注意的是,这跟WPF中常用的ObservableCollection<T>的实现方式是不同的。

简单使用

从wpf中常用的ObservableCollection<T>得到IObservable<ChangeSet>

csharp 复制代码
// 'myList' is ObservableCollection<T>
// 'myDerivedList' is IObservableList<T>
var myDerivedList = myList
    .ToObservableChangeSet()
    .Filter(t => t.Status == "Something")
    .AsObservableList();

// 'myList' is ObservableCollection<T>
// 'myDerivedCache' is IObservableCache<T, TKey>
var myDerivedCache = myList
    .ToObservableChangeSet(t => t.Id)
    .Filter(t => t.Status == "Something")
    .AsObservableCache();

以上两种方式是线程不安全的,加入myList绑定到了View上,那么在View上也可能对myList进行更改。推荐的方法是先创建一个数据源。

csharp 复制代码
var myList = new SourceList<T>()
var disposable = myList
    .Connect() // 获得IObservable<ChangeSet>
    .\\some other operation

这种方法的好处是可以在后台线程上进行维护。比如:

csharp 复制代码
//ReadOnlyObservableCollection可以多线程操作
ReadOnlyObservableCollection<T> bindingData;
var disposable = mySource
    .Connect() // make the source an observable change set
    .Sort(SortExpressionComparer<T>.Ascending(t => t.DateTime))
    .ObserveOn(RxApp.MainThreadScheduler) 
    // 'mySource' 会在其他线程上更新
    .Bind(out bindingData)
    .Subscribe(); 

ReactiveUI使用动态数据

开发时,会遇到可变集合和不可变集合,当对不可变集合进行处理时,简单情况下可以使用ObservableAsPropertyHelper<T>,它包含一个Observable<T>。每次给集合赋予新的集合时会触发通知事件。

而对于可变集合,往往采用动态数据的方式。

案例

csharp 复制代码
public class Service 
{
    //定义一个数据集
    private readonly SourceList<bool> _items = new SourceList<bool>();

    //暴露给外面
    public IObservable<IChangeSet<bool>> Connect() => _items.Connect();

    public Service()
    {        
        _items.Add(true);
        _items.RemoveAt(0);
        _items.Add(false);
    }
}

ReadOnlyObservableCollection

  • 动态数据往往使用ReadOnlyObservableCollection<T>之类的类型对外公开,而不是它本身的类型。IObservable<IChangeSet<T>>IObservable<IChangeSet<TObject, TKey>>是可以观测类型,IObservable<IChangeSet<T>>中含有集合更改的内容,第一次使用ToObservableChangeSet()时会发出集合的当前状态。
  • SourceListSourceCache是可以使用多线程进行创建IObservable<IChangeSet<T>>等,通常SourceListSourceCache应该定义为Private,而是通过Connect方法暴露给View。
csharp 复制代码
public class ViewModel : ReactiveObject
{
    private readonly ReadOnlyObservableCollection<bool> _items;
    public ReadOnlyObservableCollection<bool> Items => _items;

    public ViewModel()
    {
        var service = new Service();
        service.Connect()
            // Transform 和Select方法类似,只不过是观察一个集合的变化且将元素投影到另一个集合
            .Transform(x => !x)
            // Filter 类似于Where
            .Filter(x => x)
            // 确保更先到UI线程.
            .ObserveOn(RxApp.MainThreadScheduler)
            // 通过 .Bind() 方法实现可变集合包含新的数据并且刷新UI
            .Bind(out _items)
            .Subscribe();
    }
}

ObservableCollectionExtended

ObservableCollectionExtended<T>是一个单线程集合,如果要同步VM中的两个集合,可以将其中一个声明为ObservableCollectionExtended<T>,另一个声明为ReadOnlyObservableCollection<T>,然后使用.ToObservableChangeSet()方法将其转换为IObservable<IChangeSet<T>>

csharp 复制代码
public class SynchronizedCollectionsViewModel : ReactiveObject
{
    private readonly ReadOnlyObservableCollection<bool> _derived;
    public ReadOnlyObservableCollection<bool> Derived => _derived;

    public ObservableCollectionExtended<bool> Source { get; }

    public SynchronizedCollectionsViewModel()
    {
        Source = new ObservableCollectionExtended<bool>();
        
        Source.ToObservableChangeSet()
            .Transform(value => !value)
            // 在这里不需要使用ObserveOn更新UI线程,因为它是单线程
            .Bind(out _derived)
            .Subscribe();
     
        Source.Add(true);
        Source.RemoveAt(0);
        Source.Add(false);
        Source.Add(true);
    }
}

根据集合中的更改

ReactiveObject类实现了INotifyPropertyChanged,动态数据可以对ReactiveObject类进行跟踪。

csharp 复制代码
// 'collectionOfReactiveObjects' 是 ObservableCollection<T>
//  T inherits 继承自 ReactiveObject
// 'databasesValid' 则是 IObservable<bool>
var databasesValid = collectionOfReactiveObjects
    .ToObservableChangeSet()
    .AutoRefresh(model => model.IsValid) // 订阅IsValid属性的更改
    .ToCollection()                      // 获取新项目集合
    .Select(x => x.All(y => y.IsValid)); // 验证是否满足条件.

// 将IObservable<bool> 转为视图模型
// '_databasesValid' 是ObservableAsPropertyHelper<bool> 类型
_databasesValid = databasesValid.ToProperty(this, x => x.DatabasesValid);

ReactiveList转为动态数据

如果使用的是ReactiveList<T>,并且仅从UI线程添加/删除,则使用ObservableCollectionExtended<T>

相关推荐
周杰伦fans8 小时前
AutoCAD .NET 二次开发:深入理解 EntityJig 的工作原理与正确实现
开发语言·.net
小王毕业啦8 小时前
2005-2024年 省级-总抚养比、儿童抚养比、老年人抚养比数据(xlsx)
大数据·人工智能·数据挖掘·数据分析·社科数据·实证分析·经管数据
2501_927283589 小时前
荣联汇智助力天津艺虹打造“软硬一体”智慧工厂,全流程自动化引领印刷包装行业数智变革
大数据·运维·数据仓库·人工智能·低代码·自动化
还是奇怪11 小时前
AI 提示词工程入门:用好的语言与模型高效对话
大数据·人工智能·语言模型·自然语言处理·transformer
Data_Journal12 小时前
如何使用cURL更改User Agent
大数据·服务器·前端·javascript·数据库
weixin_4462608512 小时前
城市智能化的底层基石:基于腾讯地图服务生态的移动定位与导航架构指引
大数据·人工智能·架构
qq_2837200513 小时前
Vibe Coding 氛围编程入门教程:AI 时代的全新开发范式(零基础到实战)
大数据·人工智能
Volunteer Technology13 小时前
ES并发控制
大数据·elasticsearch·搜索引擎
小飞象—木兮14 小时前
《销售数据分析标准实践手册》:核心内涵与关键指标、落地销售数据分析的全流程···(附相关材料下载)
大数据·人工智能·数据挖掘·数据分析
盟接之桥14 小时前
什么是EDI(电子数据交换)|制造业场景解决方案
大数据·网络·安全·汽车·制造