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

10

以下是一个详细的示例:

我正在使用一个ItemsControl在我的View中动态创建一个简单的条形图,并将项绑定到我的BarGraphViewModel中包含百分比值的BarViewModels集合中。 每个条形应该有不同的颜色。这些颜色应该从一个集合中选择,例如{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,并传递从我的颜色集合创建的适当的 ColorBrush。

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

现在,因为它包含 SolidColorBrush 类型的属性,我的 ViewModel 依赖于 Presentation framework,如果我想在另一个环境中使用它,则必须进行更改。

因此,这是否违反了 MVVM 最佳实践,还是可以接受的(你必须画一条线,否则事情就会变得太复杂)

我只是想知道其他人对此有什么看法,是否有其他解决方案可以使 ViewModel 完全不了解 Presentation Layer 而不会过于复杂。我可以想象 ValueConverters 可以帮助解决这个问题?

3个回答

9
在马丁·福勒(Martin Fowler)描述的原始演示模型模式中,视图“询问”视图模型如何显示自己。这似乎更倾向于在视图模型上放置颜色和大小属性而不是在视图上放置触发器。然而,在WPF中应用此模式有所不同。在WPF中,您通常使用视图中的样式和数据模板来定义视图的外观。直接从视图模型返回特定颜色将与此方法相违背。因此,简短的答案是:不要在视图模型上放置颜色属性。
此外,在原始演示模型模式中,视图模型是视图的抽象。因此,它不会返回确切的颜色,最好返回一个“键”,然后视图可以使用该键查找实际的颜色。例如,PersonViewModel.FaceColor返回Red,你可以让PersonViewModel.Mood返回Angry。然后,视图可以使用样式或数据模板触发器将其转换为实际的红色颜色。
这就是我的答案,并且我坚持这一点,但考虑到另一方面的论点也很有趣。首先,在视图模型上放置颜色属性仍然可进行单元测试,这似乎已成为视图模型中什么是可以接受的的主要标准。
保持对视图技术的“不可知性”并不是两者之间的重要因素。保持视图模型与其他视图技术的二进制兼容性的目标仅在XAML系列中是现实的。将所有视图模型移动到没有直接依赖于WPF的自己的项目中是一个好主意。但是,您必须排除使用ICommand的任何内容,或者为WindowsBase.dll引用做出例外。从实际角度来看,它不会给您带来太多好处。我们几乎完全粘在微软技术上!如果您决定转移到另一个GUI框架,则我猜您正在寻找源代码转换。如果您决定将颜色类型放入视图模型中,则迁移可能包括更改颜色类型。虽然这不是反对在视图模型上放置颜色属性的原因,但也不是必须在视图模型上放置颜色属性的原因。

看到我回答的最近赞数,我想提一下,在.NET 4.5中,可移植类库(PCL)允许在Microsoft的XAML技术(WPF、Silverlight和Metro风格应用程序)之间进行视图模型的二进制共享。在PCL中,您可以将ICommand引用为跨XAML技术相同的接口。然而,我不认为颜色或画笔在这些技术之间是二进制兼容的。 - HappyNomad

8
理论上,你所描述的情况违反了MVVM的最佳实践。但是有一种简单的解决方案可以清理你的视图模型。你应该创建自己的类型来表示视图模型中的颜色——它可以是字符串、整数或枚举。然后,你可以编写自定义的ValueConverter(实现IValueConverter)来将视图模型颜色类型转换为表示框架相关的颜色表示。转换器应该与绑定表达式一起使用。 有关转换绑定值的示例在此处

2

我认为你的VM上述代码没有技术问题,但我个人会使用 Brush 而不是一个特定的子类。我认为这并不违反MVVM最佳实践,因为你的VM是你的视图模型。它不一定要对构建视图的技术不感兴趣。

然而,还有其他原因为什么它可能是一个坏主意。你的视图模型是否可能在非WPF环境中使用?如果是,你需要一个可以转换为平台特定结构的抽象,例如WPF的 Brush。并且不一定需要使用转换器来实现此功能。你的抽象本身可以是一个视图模型,然后具有平台特定的子类。例如,你可能会有一个 Color 视图模型和一个从其继承的 WpfColor 视图模型。

你的团队是否有设计师?如果有,那么在你的VM中使用 Brush 可能会阻碍他们自定义UI的能力。虽然你上述的情况可能是一个例外,但总的来说,设计师和开发者的协作受益于VM公开状态,并渲染该状态。一旦VM以任何方式指定了视觉外观,你就限制了设计师可以做出的决策。

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


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接