我在 MSDN 上读到,必须使用 2 个参数声明 ThemeInfo,这些参数负责控制主题特定位置和通用特定位置,尽管我不知道什么是“主题”和什么是“通用”。我怎样才能更好地理解这两个?
基本上,WPF 框架将查找名称与操作系统主题名称匹配的 xaml 资源。因此,如果您在 XP 上运行蓝色主题为“luna.normal.xaml”。如果找不到具有该确切名称的名称,它将查找“generic.xaml”。实际上,我认为如果他们没有找到与操作系统特定的匹配的“classic.xaml”,他们首先会寻找“classic.xaml”,然后他们会寻找generic.xaml。您可以将 generic.xaml 视为默认资源。
ThemeInfo 属性只是告诉 WPF在哪里定义了这些资源。有 3 个选项:
-
无 - 您没有提供“主题”或“通用”资源。这确实是一种优化,因此 WPF 框架不会费心寻找它们。您通常不会将其用于 GenericDictionaryLocation,但您可以将其用于 ThemeDictionaryLocation,以防您不打算定义操作系统主题特定的资源(即您没有不希望您的控件在不同的操作系统主题下看起来不同)。通常,控件供应商会为每个可能的操作系统主题定义一个资源字典,以便控件看起来与该操作系统中运行的其他控件和窗口一致。
-
ExternalAssembly - 这意味着您正在为资源定义一个单独的程序集。因此,如果您查看 WPF 框架,您会看到他们将其用于 ThemeDictionaryLocation 的 PresentationFramework 程序集。然后他们为他们想要支持的每个操作系统主题定义了一个单独的程序集(例如 PresentationFramework.Aero.dll、PresentationFramework.Luna.dll 等)。它将搜索的程序集名称是定义程序集的名称加上主题的名称。
-
SourceAssembly - 这意味着资源是在程序集本身内定义的。因此,在该程序集中,您将拥有一个包含资源字典的“主题”文件夹。
This article on MSDN 关于控件创作的信息对于提供这方面的信息确实还不错。
也有人可以告诉我如何使用 ThemeInfo 告诉我的“MyCustomControls.dll”使用“MyAnotherCustomControls.dll”中定义的字典资源吗?这是否可以仅通过 ThemeInfo 完成,或者我是否必须处理“MyCustomControls.dll”中的 MergedDirectories?我希望 WPF 系统负责定位资源,以便我可以使用“MyAnotherCustomControls.dll”中的样式键,而无需在“MyCustomControls.dll”中添加合并目录。
您不能使用 ThemeInfo 告诉 WPF 它应该在某个任意程序集中查找您的资源。话虽如此,如果您不设置或覆盖 DefaultStyleKey,就像在定义自定义控件时通常所做的那样,那么它应该继续使用已设置 DefaultStyleKey 的基类的资源/被默认资源覆盖。
但应注意 local 样式解析(即,当您的控件的 Style 属性未设置并且 WPF 从元素所在的位置查找并向上走视觉/逻辑树查找可能隐式影响该元素的 Style)将总是查找其 Key 与类的确切类型匹配的 Style。因此,如果有一个 Style,其 TargetType(因此放置在 ResourceDictionary 中时的默认键)是在窗口的资源中定义的 TextBox,它将影响该窗口中的所有 TextBox 实例(除非它们在视觉中具有更接近的样式树 - 即在其自身之间的某个元素的资源中定义某个祖先 - 或其 Style 属性已设置)。但是,如果您有一个派生自 TextBox 的类(例如 MyTextBox 类:TextBox),那么它将不会选择/使用该样式。相反,它将寻找 TargetType/Key 为 typeof(MyTextBox) 的 Style。解决这个问题的一种方法是将 Style 属性设置为 DynamicResource 为基本类型。例如
public MyTextBox()
{
this.SetResourceReference(StyleProperty, typeof(TextBox));
}
基本上,这会在控件的 Style 属性上设置一个本地值,该属性正在为一个 Style 进行动态资源查找,该 Style 的 Key(以及未设置 x:Key 的 Styles 的 TargetType)是指定类型(在本例中为 TextBox )。
正如您所指出的,替代方法是在您的程序集中本地为基类程序集定义的每个主题定义 xaml 文件,然后将 ResourceDictionary 添加到其 MergedDictionaries 中,使用 pack uri notation 来引用基类中的资源部件。如果您要设置 DefaultStyleKey,那么您可能需要在每个 ResourceDictionaries 中定义 TargetType 是您的类类型的 Style,然后将 BasedOn 设置为 StaticResource,其中资源键是基类的类型。听起来您不需要这样做。