ReactiveUI 使用 WhenAny 观察 Collection 并分配布尔值 PropertyHelper

ReactiveUI observing Collection with WhenAny and assigning boolean PropertyHelper

我有一个包含我想要观察的字符串的 ObservableCollection。当第一个索引发生变化时,我想更新一个 ObservableAsPropertyHelper 布尔变量,如果该索引处的字符串不为空且不为空,则将其设置为 true 。或者,将 Collection 转换为第二个包含 bool 的 ObservableCollection 的方法也可以。
这是我尝试过的:

public ObservableCollection<string> Difficulties { get; set; }
public extern bool Easy { [ObservableAsProperty] get; }

public Song()
{
    this.WhenAny(x => x.Easy, x => x.GetValue()[0] != null && x.GetValue()[0}]!= "").ToPropertyEx(this, x => x.Easy);
}

我尝试了上面的代码,因为它适用于类似的示例:

[Reactive] public string Title { get; set; }
public extern bool Enabled { [ObservableAsProperty] get; }

public Song()
{
   this.WhenAny(x => x.Title, x => x.GetValue() != null && x.GetValue() != "").ToPropertyEx(this, x => x.Enabled);
}

我对使用 Linq 表达式还很陌生,所以解决方案可能很简单(比我尝试过的东西要简单得多 -_-)
顺便说一句,我在 .net core 3.0 上使用 ReactiveUi.WPF 和 ReactiveUi.Fody。

WhenAnyValue 扩展方法通常用于您想观察视图模型属性变化的情况,并且在这方面非常出色。它并非设计用于可变集合,例如 ObservableCollectionReadOnlyObservableCollection。对于反应性集合,也可以使用 DynamicData library, see the related documentation page。最新的 ReactiveUI 版本依赖于 DynamicData,因此您不必安装任何额外的包。

TLDR;

  1. 如果您有 T 类型的 属性,则使用 WhenAnyValue.

  2. 如果您有 ObservableCollection<T> 类型的 属性,请使用 ToObservableChangeSet

[ObservableAsProperty] 
public bool Easy { get; }

public ObservableCollection<string> Difficulties { get; }

public Song()
{
    Difficulties = new ObservableCollection<string>();

    // Observe any changes in the observable collection.
    // Note that the property has no public setters, so we 
    // assume the collection is mutated by using the Add(), 
    // Delete(), Clear() and other similar methods.
    this.Difficulties
        // Convert the collection to a stream of chunks,
        // so we have IObservable<IChangeSet<TKey, TValue>>
        // type also known as the DynamicData monad.
        .ToObservableChangeSet(x => x)
        // Each time the collection changes, we get
        // all updated items at once.
        .ToCollection()
        // If the collection isn't empty, we access the
        // first element and check if it is an empty string.
        .Select(items => 
            items.Any() &&
            !string.IsNullOrWhiteSpace(items.First()))
        // Then, we convert the boolean value to the
        // property. When the first string in the
        // collection isn't empty, Easy will be set
        // to True, otherwise to False.
        .ToPropertyEx(this, x => x.Easy);
}

请注意,如果您使用的是不可变数据集,例如有点像这样:

[Reactive] public IEnumerable<string> Difficulties { get; set; }

并且该数据集仅通过其 public setter 更新,那么您应该在此处使用 WhenAnyValue 扩展方法,因为声明为 IEnumerable<string> 的集合不是无法观察到:

this.WhenAnyValue(x => x.Difficulties)
    .Select(items => 
        items.Any() &&
        !string.IsNullOrWhiteSpace(items.First()))
    .ToPropertyEx(this, x => x.Easy);