3

我正在学习 MVVM。

我的 View 填充了 ViewModel 中 ObservableCollection 属性的两个组合框(例如属性“ Oc1 ”和“ Oc2 ”)。我还有一个属性绑定到Oc2所依赖的Oc1的选定项(例如属性“ SelVal ”) ,因此当属性SelVal更改时,Oc2需要从数据库中重新获取它的数据。

现在,我想出了一个解决方案,它适用于我的情况,但似乎不遵守获取访问器的原则,所以我想知道我可能会遇到什么问题,什么是更好的解决方案?

我目前的解决方案是:

Oc2get访问器查询数据库并将其私有字段设置为从数据库返回的值(视图使用该值)。因此,当SetVal更改时,我只需在SetVal集合访问器中调用 this.RaisePropertyChanged(" Oc2 ") ,然后视图会请求Oc2,后者又会查询数据库并返回更新后的列表。问题是我没有使用get访问器来实现它的用途,因为我在其中分配了它的价值。但我喜欢它的是它是自包含的(即我不需要一个“BindOc2”方法,我必须在构造函数中调用,然后在 SelVal集中再次调用 存取器)。请指教。还有什么更好的方法?

4

5 回答 5

2

您的怀疑是正确的,这种方式破坏了 MVVM 模型并且无法使用可以简化您的工作的机制,例如Expression Blend SDK中可用的System.Windows.Interactivity中的触发器。

在 getter 中加载数据是自找麻烦。它将您的模型绑定到数据访问代码,通过在同一属性中混合不同的关注点,使测试更加困难并且代码更加复杂。此外,墨菲定律规定,在某些时候您只想设置属性而不从数据库重新加载。

更好的解决方案是在可以由命令或触发器调用的单独方法中提取数据加载代码。此方法将修改 Oc2 集合的内容或简单地将其替换为新集合。在任何情况下,属性设置器都会发出正确的通知,并且第二个组合将被更新。

以下示例来自fabien在类似 SO question 中的回答:

<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提供 了在 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} />
于 2012-06-12T07:00:38.527 回答
2

我理解你的沉默,因为是的,为不同的属性提高 PropertyChanged 感觉有点笨拙,但恕我直言,这还不错。

一种更自然的方法是让您的数据库拉入SelValsetter,因为这是触发数据更改的原因。然后,您将结果设置Oc2为将自动提高 a 的结果PropertyChanged

唯一的问题是,如果您的 Oc2 getter 从未被访问过,您可能会不必要地提取 db 结果,但鉴于您知道您的视图将始终需要它们,我很想更改为此解决方案。

于 2012-06-12T08:30:51.000 回答
1

你这样做的方式很好。属性 set 和 get 方法通常适用于这种 Binding

于 2012-06-12T03:24:18.137 回答
1

所以换个说法,你有一些类似于 Category、CurrentCategory 和 SubCategory 的东西。当 CurrentCategory 发生变化时,SubCategory 需要刷新。

我觉得你的方法很好。尤其是在 MVVM 中,我到处都能看到这种类型的东西。在 MVVM 之外,对于延迟加载场景(通常调用某种服务方法,而不是内联所有内容),让属性获取器访问数据库是相当常见的。

于 2012-06-12T05:09:13.797 回答
1

如果这些数据没有改变,你可以在你的视图模型中拥有它。

始终查询数据库不应该是第一选择。

你可以用一种非常简单的方式做到这一点:

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
}
于 2012-06-12T06:13:31.933 回答