ViewModel中的WPF相关属性是否违反了MVVM最佳实践?

时间:2009-12-13 14:09:50

标签: wpf mvvm separation-of-concerns

以下是一个详细说明的案例:

我在我的视图中使用ItemsControl动态创建一个简单的条形图,并将项目绑定到我的BarGraphViewModel中的BarViewModel集合(每个包含一个值的百分比)。 每个酒吧应该有不同的颜色。颜色应该从一个集合中选择,例如{Color1, Color2, ..}

集合本身是不变的,但条数将取决于具体情况。

一个简单的解决方案是创建一个简单的BarViewModel,如下所示:

public class BarViewModel
{
    public int Percentage { get; set; }

    public SolidColorBrush Stroke { get; private set; }

    public BarGraphViewModel(SolidColorBrush stroke)
    {
        Stroke = stroke;
    }
}

(为了简洁,我省略了属性更改和验证实现)

现在我可以从我的BarGraphViewModel为每个百分比创建一个BarViewModel,并传入从我的Color集合创建的相应ColorBrush。

然后在Xaml中,我将创建一个简单的ItemsTemplate,它将绑定到这些属性。

只是现在,因为它包含一个SolidColorBrush类型的属性,我的ViewModel依赖于Presentation框架,如果我想在另一个环境中使用它,它将不得不被更改。

这是否会打破MVVM最佳实践,或者它是否可以接受(你必须在某处画线或者事情变得太复杂)

我只是想看看其他人对此的看法以及是否有其他解决方案让ViewModel完全不了解Presentation Layer而不会太复杂。 我可以想象ValueConverters可以提供帮助吗?

3 个答案:

答案 0 :(得分:6)

理论上,您所描述的情况违反了MVVM中的最佳实践。但是有一个简单的解决方案可以清理您的视图模型。您应该创建自己的类型来表示视图模型中的颜色 - 它可以是string,int或enum。然后,您可以编写自定义ValueConverter(实现IValueConverter)以将视图模型颜色类型转换为依赖于表示框架的颜色表示。转换器应与边界表达式一起使用。 转换边界值的示例是here

答案 1 :(得分:6)

在Martin Fowler描述的原始Presentation Model模式中,视图“询问”视图模型如何显示自身。这似乎有利于在视图模型上放置颜色和大小属性,而不是在视图中使用触发器。然而,在WPF中应用这种模式有些不同。在WPF中,您通常使用视图中的样式和DataTemplates定义视图的 。直接从视图模型返回特定颜色将与此方法相反。所以简短的回答是:不,不要在你的视图模型上添加颜色属性。

在原始的Presentation Model模式中,视图模型是视图的抽象。因此,不是返回确切的颜色,最好返回一个“键”,然后视图可以用来查找实际颜色。例如,代替PersonViewModel.FaceColor返回Red,你将有PersonViewModel.Mood返回Angry。然后,视图可以使用Style或DataTemplate触发器将其转换为实际的红色。

所以这是我的答案,我坚持不懈,但从另一个方向考虑争论也很有趣。首先,在视图模型上放置颜色属性仍然是单元可测试的,这似乎已经成为视图模型中可行的主要标准。

对视图技术保持“不可知”并不是两个方向的重要因素。保持视图模型与其他视图技术的二进制兼容性的目标仅在XAML系列中是现实的。将所有视图模型移动到他们自己的项目,这个项目缺乏对WPF的直接依赖是个不错的主意。但是您必须排除使用ICommand的任何内容,或者对WindowsBase.dll引用进行例外处理。但实际上,它不会给你带来太大的收益。我们非常关注Micrsoft技术!如果您决定移植到另一个GUI框架,那么我的猜测是您正在查看源代码转换。我等着看微软是否在我尝试之前就已经解决了;)移植可能包括改变你的颜色类型,如果你决定把它们放在你的视图模型中。虽然不是视图模型中颜色属性的原因,但它也不是理由。

答案 2 :(得分:1)

我认为上面的虚拟机不是技术的原因,但是个人会使用Brush而不是特定的子类。我不相信这会打破MVVM最佳实践,因为您的VM是您视图的模型。它不一定必须与构建视图的技术无关。

然而,还有其他原因可能是一个坏主意。您的视图模型是否可能在非WPF环境中使用?如果是这样,您将需要一个抽象,然后可以将其转换为特定于平台的构造,WPF的Brush就是这样的一个例子。并不一定需要转换器。您的抽象本身可以是一个视图模型,然后具有特定于平台的子类。例如,您可能拥有Color视图模型,以及从中继承的WpfColor视图模型。

你的团队中有设计师吗?如果是这样,在VM中使用Brush可能会影响他们自定义UI的能力。上面的具体情况可能是异常值,但一般来说,设计人员和开发人员协作可以从VM公开状态和视图呈现该状态中获益。一旦VM以任何身份决定视觉外观,您就限制了设计师可以做出的决定。

根据我的经验,第二个原因是在VM中不包含特定于UI的构造的更常见的原因。