我正在学习MVVM。
我的View在我的ViewModel中填充ObservableCollection属性中的两个组合框(例如属性“ Oc1 ”&amp;“ Oc2 ”)。我还有一个属性绑定到 Oc1 的选定项目(例如属性“ SelVal ”) Oc2 依赖于,所以当属性< strong> SelVal 已更改, Oc2 需要从数据库重新获取数据。
现在,我已经提出了一个解决方案,它适用于我的情况,但似乎并不遵循 get 访问器的原则,所以我想知道可能会出现什么问题我面向赛道,什么是更好的解决方案?
我目前的解决方案是:
Oc2 的 get 访问者查询数据库并将其私有字段设置为从数据库返回的值(View使用的值)。因此,当 SetVal 更改时,我只需在 SetVal 设置访问者中调用this.RaisePropertyChanged(“ Oc2 ”)并且View要求 Oc2 ,后者又查询数据库并返回更新的列表。 问题是我没有使用 get 访问器来实现其目的,因为我在其中分配了它的值。但我喜欢它的是它是自包含的(即我不需要一个“BindOc2”方法,我必须在构造函数中调用,然后再在SelVal set 访问器中调用) 。请指教。什么是更好的方式?
答案 0 :(得分:2)
您的怀疑是正确的,这种方式打破了MVVM模型并且无法使用可以简化工作的机制,例如System.Windows.Interactivity中提供的Expression Blend SDK中的触发器。
将数据加载到getter中是在乞求麻烦。它将您的模型绑定到数据访问代码,通过混合同一属性中的不同关注点,使测试更加困难,代码更复杂。此外,墨菲定律规定,在某些时候,您只需要设置属性而无需从数据库重新加载。
更好的解决方案是使用可由命令或触发器调用的单独方法提取数据加载代码。此方法将修改Oc2集合的内容,或者只是将其替换为新集合。在任何情况下,属性设置器都会引发正确的通知,第二个组合将被更新。
以下示例来自fabien's answer类似的问题:
<ComboBox x:Name="fileComboBox" ItemsSource="{Binding FileList, Mode=TwoWay}">
<i:Interaction.Triggers>
<i:EventTrigger EventName="SelectionChanged">
<i:InvokeCommandAction
Command="{Binding SelectionChangedCommand}"
CommandParameter="{Binding SelectedItems,
ElementName=fileComboBox}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</ComboBox>
大多数框架都为此设计提供支持。 Caliburn.Micro提供actions,它将在发生UI事件时调用ViewModel方法,并提供快捷语法以避免编写触发器XAML和相应的命令。它只是将事件连接到ViewModel方法。 XAML可以这么简单:
<ComboBox x:Name="Oc1"
cal:Message.Attach="[Event SelectionChanged] =
[Action ReloadFor($this.SelectedItem)]" />
$this
值是引用ComboBox本身的另一种简写。
如果您不想使用触发器,可以将组合的SelectedItem属性绑定到ViewModel属性,并在此属性更改时执行Reload方法,例如:
<ComboBox ... SelectedItem={Binding CurrentOC2,Mode=TwoWay} />
答案 1 :(得分:2)
我理解你的沉默,因为提升PropertyChanged为一个不同的财产感觉有点hacky,但它不是太糟糕恕我直言。
更自然的方法是在SelVal
setter中进行数据库拉取,因为这是触发数据更改的原因。然后,您将Oc2
设置为结果,该结果将自动提升PropertyChanged
。
唯一的问题是,如果从未访问过Oc2 getter,你可能会不必要地提取db结果,但鉴于你知道你的视图总是需要它们,我很想改变这个解决方案。
答案 2 :(得分:1)
你做的方式很好。属性集和get方法通常适用于这种Binding
答案 3 :(得分:1)
所以换句话说你有类似于Category,CurrentCategory和SubCategory的东西。当CurrentCategory更改时,SubCategory需要刷新。
我认为你的方式很好。特别是在MVVM中,我看到了这种类型的东西。在MVVM之外,让属性获取者在延迟加载场景中访问数据库是很常见的(通常调用某种服务方法,而不是内联所有内容)。
答案 4 :(得分:1)
如果这些数据没有变化,您可以在viewmodel中进行更改。
始终查询数据库不应该是第一个选项。
你可以用一种非常简单的方式做到这一点:
Dictionary<string, List<string>> cache;
...
List<string> subCat;
if cache.TryGetValue (selVal, out subCat)
{
// no need to call database
}
else
{
// else call database
// insert result in cache
}