WPF基础:MVVM共享全局样式

8

我尝试使用MVVM风格的方法进行WPF开发。

我将逻辑视图模型类放在ViewModel命名空间下,并且为这些视图模型类设置了匹配的样式,放在View命名空间中。

目前,我将View信息作为DataTemplates和Styles保存在ResourceDictionary XAML文件中,并将它们全部合并到app.xaml中的单个App.Resources ResourceDictionary中。

然而,我遇到了一种鸡生蛋/蛋生鸡的问题。我想要有全局样式可以在许多地方使用。例如,我想要自定义一个叫做MonkeyText的文本样式,可以在各种样式中使用。我不能只在app.xaml文件中设置这个样式,因为会使用MonkeyText的ResourceDictionary也被包含在那个app.xaml文件中。

如果这是不可能的,那么另一种选择是使用UserControl来建立我的视图,而不是大多数情况下使用DataTemplate。但我担心使用UserControl会将VM和V部分联系得太紧密。

1个回答

11

WPF提供了DynamicResources来解决这个问题。StaticResources最像编程中传统的引用方式,但它们有一个你遇到的问题:在样式被解析之前,需要定义和加载它们。另一方面,DynamicResources不需要在使用它们之前进行定义-实际上,您甚至可以在运行时创建它们。WPF会确保所有引用DynamicResources的样式在它们实际加载后自动加载。

使用DynamicResources非常简单。当您创建MonkeyText样式时,按照通常的方式创建:

<Style TargetType="TextBlock" x:Key="MonkeyText">
    <Setter Property="TextAlignment" Value="Center"/>
    <!-- etc. -->
</Style>

然后可以使用 DynamicResource 从其他地方引用它:

<TextBlock Text="Hello, World!" Style="{DynamicResource MonkeyText}"/>

如果因为任何原因,WPF 无法解析您的 DynamicResource,则会在默默地失败,而不会抛出任何异常(当 StaticResources 无法解析时会抛出异常)。但是,在发生这种情况时,它会打印一个调试消息 - 因此请注意 Visual Studio 中的输出窗口。

由于 DynamicResources 与在任何时间点以任何顺序加载的资源一起工作,因此您可以按任何方式结构化资源字典 - 因此将它们放在其他视图样式中并通过单个 App.Resources ResourceDictionary 在 app.xaml 中合并它们将运行良好。

有关 DynamicResources 的更多详细信息可以在 WPF 的 MSDN 文档中找到。


我对这个问题自己也一直很好奇,感谢你的回复。除了一些小应用程序外,我从未深入研究过WPF。另外,你是如何级联依赖视图模型的呢?你只有一个“应用程序视图模型”,还是有一个“主视图模型”和“子视图模型”以及“后代视图模型”? - Firoso
通常情况下,您会有一个“主”视图模型,然后您的模型对象由它引用并形成一些层次结构。这比较复杂,并且在某种程度上取决于应用程序中数据的结构 - 但这是简短版本。 - Nicholas Armstrong
但是如果您想要在所有TextBlock上使用MonkeyText呢?在普通的WPF中,您可以在App.xaml中声明样式,并且由于TargetType的存在,它将适用于所有TextBlock。但是在使用MVVM时,似乎不起作用,除非我在所有控件上声明DynamicResource。 - Peter
MVVM和资源是正交的概念;资源适用于MVVM中的第一个“V”,即“View”。在MVVM风格的应用程序中,您可以使用任何混合StaticResources和DynamicResources的方式 - MVVM风格的应用程序只是一个“普通的WPF”应用程序,其作者决定遵循特定的架构模式。您可以像传统方式一样设置控件的默认样式 - 通过不给样式指定键或将键设置为控件的类型名称。 - Nicholas Armstrong

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