Ada*_*ley 6 wpf user-interface f# immutability observer-pattern
在上一个问题中,我问过如何习惯性地为F#应用程序实现一个观察者模式.我的应用程序现在使用MailboxProcessor作为推荐,我已经创建了一些辅助函数来创建子邮箱处理器等.但是,当涉及到GUI绑定的特定案例场景时,我处于心理障碍.
让我们说我有一个模型:
type Document = {
Contents : seq<DocumentObject>
}
Run Code Online (Sandbox Code Playgroud)
GUI(WPF,XAML)需要绑定,如下所示:
interface IMainWindowViewModel
{
IEnumerable<Control> ContentViews { get; }
}
Run Code Online (Sandbox Code Playgroud)
每个ViewModel每个Control都需要一个DocumentObject(其底层模型),并知道它是否已经改变的一种方式.我提供这个作为一个子项,MailboxProcessor<DocumentObject>以便可以正确传播更改,我对这种模式有效.本质上,它映射服务输出并包装修改请求(下面的外部接口示例):
let subSvc = generateSubSvc svc (fun doc -> doc.Contents[0]) (fun f -> fun oldDoc -> { oldDoc with Contents[0] = f Contents[0] })
let viewModel = new SomeDocObjViewModel(docObjSvc)
new DocObjView(viewModel)
Run Code Online (Sandbox Code Playgroud)
现在,想象一个修改命令现在删除DocumentObject的MyDocument.顶级MailboxProcessor现在回应IMainWindowViewModel使用它的变化IEvent<MyDocument>.这就是我的问题开始的地方.
我IMainWindowViewModel真的不知道 哪个DocumentObject被删除了.只有那是一个新的Document,它必须处理它.可能有一些方法可以搞清楚,但它从来没有直接知道.这可以迫使我倒不必任何的路径重新创建所有Control的所有DocumentObject的是安全的(低效率).还有其他问题(例如悬空subSvc),为简洁起见,我在这里也没有提到.
通常情况下,这些动态变化会被处理成类似的东西ObservableCollection<DocumentObject>然后被映射到一个ObservableCollection<Control>.这伴随着共享可变状态的所有警告,并且有点'hackish'; 然而,它确实做到了.
理想情况下,我想要一个"纯粹"的模式,从的派头自由PropertyChanged和ObservableCollections有什么样的F#中的模式将满足这方面的需求?在惯用语和现实语之间画出界线是恰当的吗?
您是否考虑过使用响应式扩展(以及未来的响应式 UI )以功能性方式对可变状态进行建模(阅读:随时间变化的模型属性)?
我认为在您的模型中使用 an 在技术上没有任何问题ObservableCollection。毕竟,您需要跟踪集合更改。您可以自己完成,但看起来您可以为自己节省很多重新发明可观察集合的麻烦,除非您有非常具体的理由避免使用该类ObservableCollection。
另外,使用MailboxProcessor似乎有点矫枉过正,因为您可以使用 a Subject(来自 Rx)来发布并将其公开IObservable为订阅“消息”:
type TheModel() =
let charactersCountSubject = new Subject()
let downloadDocument (* ... *) = async {
let! text = // ...
charactersCountSubject.OnNext(text.Length)
}
member val CharactersCount = charactersCountSubject.AsObservable() with get
type TheViewModel(model : TheModel) =
// ...
member val IsTooManyCharacters = model.CharactersCount.Select((>) 42)
Run Code Online (Sandbox Code Playgroud)
当然,由于我们讨论的是 WPF,因此视图模型应该实现INPC. 有不同的方法,但无论您采用哪一种,ReactiveUI都有很多方便的工具。
例如,CreateDerivedCollection解决您提到的问题之一的扩展方法:
documents.CreateDerivedCollection(fun x -> (* ... map Document to Control ... *))
Run Code Online (Sandbox Code Playgroud)
这将获取您的documents可观察集合,并从中创建另一个可观察集合(实际上是一个ReactiveCollection),该集合将文档映射到控件。
| 归档时间: |
|
| 查看次数: |
809 次 |
| 最近记录: |