我正在做一些我从未尝试过的事情。我正在尝试创建动态UI并将其绑定到动态模型。换句话说,我的Web服务将发回我的UI的小元数据描述和要绑定到它的原始数据。因此,在构建时,我不知道我将构建什么UI,我不知道我的模型是什么。将它们捆绑在一起似乎非常困难,如果不是不可能的话。
Mvx允许我将UI直接绑定到模型,而不是它是MvxViewModel。但是,如果我直接绑定到Web服务返回的Model,我将无法使用RaisePropertyChanged(),因为它只来自MvxViewModel。
通常情况下,我会编写一个包装模型的ViewModel,让所有包装的setter调用RaisePropertyChanged()。但是,在这种情况下,我的模型是动态的,所以我不能在编译时用ViewModel包装它,因为我不知道它在运行时是什么。
我是否可以使用一些很酷的技巧来构建一个ViewModel,它可以包装任何C#模型类并发送属性更改事件,而不知道模型类在运行时具有哪些属性?
我刚刚发现DLR和DynamicObject似乎很完美,但由于Apple的限制,它不适用于Xamarin.iOS。
答案 0 :(得分:2)
在iOS上没有取笑DynamicObject
生活,主要的方法是:
您可以更改您的网络服务生成代码,以便它生成INotifyPropertyChanged
- 我已经使用了这样做的库 - 例如http://stacky.codeplex.com/SourceControl/latest#trunk/source/Stacky/Entities/Answer.cs - 如果您无法更改Web服务代码生成本身,您仍然可以使用某种t4或其他模板技巧来包装或转换生成的代码。
您可以调查某种将Web服务对象映射到某种可观察集合的代码(Kiliman在评论中建议这样做)
你可以看一下进行绑定的某种valueconverter(或者也许是valuecombiner) - 我可以很容易地想象一个valueconverter,它接受一个包装的模型对象和一个字符串参数(属性名称)并使用那些两个在一起(有一些反思)来弄清楚该怎么做。我不确定这个如何与嵌套的模型对象一起工作......但即使这样也是可能的......
您可以查看MvvmCross的某种自定义绑定扩展。这并不像听起来那么可怕,但需要一些反思技巧 - 要了解可能涉及的内容,请查看FieldBinding插件 - https://github.com/MvvmCross/MvvmCross-Plugins/tree/master/FieldBinding
在实际数据绑定过程中,插件将通过IMvxSourceBindingFactoryExtension
调用 - 这是您抓住其他自定义更改event
(而不是INotifyPropertyChanged
)的机会。可能需要一些实验才能做到这一点......特别是如果你有嵌套对象(然后在绑定中需要“链接”)......但我认为应该可以用这种方式生成东西。
答案 1 :(得分:2)
我不确定我最终确定的是否支持所有可能的功能,但到目前为止,它似乎满足了我所需要的一切。
我真的很喜欢写自己的IMvxSourceBindingFactoryExtension
的想法。但是,在调查如何做到这一点时,我开始使用MvvmCross中已存在的功能。我已经知道MvvmCross会尊重ObservableCollection
。我不知道的是我可以在绑定表达式中使用[]
并且不仅整数索引器可以工作,而且Dictionary
上的字符串索引器也可以。我发现MvvmCross示例代码在其GIT仓库中已经实现了ObservableDictionary
。事实证明,这就是我解决问题所需要的一切。
所以我的模型包含静态属性和ObservableDictionary<string,object>
动态属性,其中键是动态属性的名称,值是属性的值。
我的ViewModel
包装此模型类以发送有关静态属性的PropertyChanged
通知。由于动态属性的Dictionary
是可观察的,因此MvvmCross已经处理了对该字典成员的更改,包括双向。
最后一个问题是如何在我的绑定表达式中绑定它。这就是[]
的用武之地。如果我的ObservableDictionary
属性名称被称为UserValues
并且它包含一个值user1
的值,那么我可以双向绑定它使用:UserValues[user1]
,一切似乎都很完美。
我发现的一个问题是,我现在要求我的动态数据源向我发送ObservableDictionary
而不是Dictionary
。那要求太多了吗?