gpt4 book ai didi

c# - ReactiveUI - 具有许多相关属性的模型对象

转载 作者:太空狗 更新时间:2023-10-30 00:23:02 26 4
gpt4 key购买 nike

我有一个 WPF MVVM 应用程序。我的模型对象是我可以完全控制的 POCO。这些对象中的某些属性之间存在关系。

例如:假设我有

public class Model
{
public ObservableCollection<double> XCoordinates { get; set; } // Cumulative sum of DistancesBetweenXCoordinates.
public ObservableCollection<double> DistancesBetweenXCoordinates { get; set; } // {x[1]-x[0], x[2]-x[1], ..., x[n]-x[n-1]}
public double TotalLength { get; set; } // Sum of DistancesBetweenXCoordinates.
}

我希望最终用户能够编辑距离列表或 x 坐标列表,并且其他属性应该自动更新。到目前为止,我已经使用 INPC 事件完成了这项工作,但这很快就会变得太困惑。一些 UI 更新是在每次 PropertyChange 之后完成的,所以我想对此进行优化。

由于我的真实应用中的一些属性更新对性能的影响可以忽略不计,所以我不想使用“计算属性”,例如

public double TotalLength => DistancesBetweenXCoordinates.Sum();

据我了解,ReactiveUI 框架似乎具有我正在寻找的功能。不过我有一些问题:

1) 我目前正在使用另一个我不想完全放弃的框架 (Catel)。我可以使用 ReactiveUI 中的 .WhenAny() 等而不继承 ReactiveObject(例如,仅通过实现 IReactiveObject)吗?

2) 我见过的几乎所有示例都继承自 ViewModel 中的 ReactiveObject。这是实现我想要的目标的首选方式吗?在我的模型中实现它不是更有意义吗?如果我的模型应该只是一个“愚蠢的”POCO,没有任何机制来保持所有相关属性都是最新的,那么这是我的 Reactive VM 的责任吗?

如果能提供一个简单的示例或其他指导,我将不胜感激。

最佳答案

tl;博士

  • 实现INotifyPropertyChanged,您可以使用.WhenAny()
  • ReactiveObject 可用于 ViewModel 和 Model 类。它实际上只是一个“ react 性”对象。即像 System.Object。 (不相信我?查看 the source 。)
  • 使用 ObservableAsPropertyHelper 计算依赖于其他 react 属性或事件的属性。 (参见 docs)

答案

有几种方法可以处理这个问题,但特别是您似乎想要推理出一些事情:

  1. 如何在不从我正在使用的另一个框架迁移的情况下利用响应式功能?
  2. ReactiveObject 应该仅限于 ViewModels 吗?它在普通模型类中有用吗?

首先,您已经注意到,ReactiveUI 的很多吸引力都来自 .WhenAny() 中包含的强大功能。你能在框架之间使用这些方法吗,! .WhenAny().WhenAnyValue().WhenAnyObservable() 方法适用于任何实现INotifyPropertyChanged。 ( Related Docs )

事实上,您现有的框架很可能已经在它们自己的许多类型上实现了 INotifyPropertyChanged,因此 .WhenAny() 自然会扩展以无缝地处理这些对象。你几乎从不真正需要 ReactiveObject。它只会让您的生活更轻松。

Note: This is actually one of the core values of ReactiveUI. That at the core, ReactiveUI is really just a bunch of extension methods designed to make working with observables easier in the existing .Net world. This makes interoperability with existing code one of ReactiveUI's most compelling features.

现在,ReactiveObject 应该用于普通的“哑”模型吗?我想这取决于你希望责任归于何处。如果您希望您的模型类只包含规范化状态而根本不包含任何逻辑,那么可能不会。但是,如果您的模型旨在处理状态和领域相关的逻辑,那为什么不呢?

Note: There's a larger philosophical debate here about the single responsibility principal, software architecture, and MVVM, but that's probably for Programmers SE.

在这种情况下,我们关心通知监听器有关某些计算属性(例如 TotalLength)的更新。 (即我们的模型包含一些逻辑)ReactiveObject 帮助我们做到这一点吗?我想是的。

在您的场景中,我们希望在添加或更改元素时根据DistancesBetweenXCoordinates 计算TotalLength。我们可以结合使用 ReactiveObjectObservableAsPropertyHelper。 ( Related Docs )

例如:

class Model : ReactiveObject
{
// Other Properties Here...

// ObservableAsPropertyHelper makes it easy to map
// an observable sequence to a normal property.
public double TotalLength => totalLength.Value;
readonly ObservableAsPropertyHelper<double> totalLength;
public Model()
{
// Create an observable that resolves whenever a distance changes or
// gets added.
// You would probably need CreateObservable()
// to use Observable.FromEventPattern to convert the
// CollectionChanged event to an observable.
var distanceChanged = CreateObservable();

// Every time that a distance is changed:
totalLength = distanceChanged

// 1. Recalculate the new length.
.Select(distances => CalculateTotalLength(distances))

// 2. Save it to the totalLength property helper.
// 3. Send a PropertyChanged event for the TotalLength property.
.ToProperty(this, x => x.TotalLength);
}
}

在上面,每次 distanceChanged observable 解析时,都会重新计算 TotalLength。例如,每当 DistanceBetweenXCoordinates 发出 CollectionChanged 事件时。此外,因为这只是一个普通的可观察对象,您可以在后台线程上进行计算,从而使您可以在长时间操作期间保持 UI 响应。计算完成后,将为 TotalLength 发送 PropertyChanged 事件。

关于c# - ReactiveUI - 具有许多相关属性的模型对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45990829/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com