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

Tom*_*ier 2 c# linq lambda list reactiveui

我有一个 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);
}
Run Code Online (Sandbox Code Playgroud)

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

[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);
}
Run Code Online (Sandbox Code Playgroud)

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

Art*_*yom 5

WhenAnyValue扩展方法通常用于情况下,当你想观察视图模型性质的变化且具有优异的正是这样做的。它不是为使用可变集合而设计的,例如ObservableCollectionReadOnlyObservableCollection。对于反应式集合,请使用DynamicData库,另请参阅相关文档页面。最新的 ReactiveUI 版本依赖于 DynamicData,因此您无需安装任何其他软件包。

TLDR;

  1. 如果您有一个 type 属性T,则使用WhenAnyValue.

  2. 如果您有一个 type 属性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);
}
Run Code Online (Sandbox Code Playgroud)

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

[Reactive] public IEnumerable<string> Difficulties { get; set; }
Run Code Online (Sandbox Code Playgroud)

并且该数据集仅通过其公共设置器更新,那么您应该在WhenAnyValue此处使用扩展方法,因为声明为的集合IEnumerable<string>不可观察:

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