如何编写风格化但独立于操作系统的 WPF 控件。使用 Microsoft.Windows.Themes
Posted
技术标签:
【中文标题】如何编写风格化但独立于操作系统的 WPF 控件。使用 Microsoft.Windows.Themes【英文标题】:How to write a stylized but OS independent WPF controls. Using Microsoft.Windows.Themes 【发布时间】:2020-09-08 08:02:51 【问题描述】:我正在寻找一篇文章,该文章将描述编写可在不同版本的操作系统下工作的程式化控件的理论。 Windows 10、8、7,经典主题。
我正在尝试在我的 XAML 代码中使用 DataGridHeaderBorder 类。
如果我这样写
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:theme="clr-namespace:Microsoft.Windows.Themes"
xmlns:local="clr-namespace:EhLib.WPF">
...
<Grid>
<theme:DataGridHeaderBorder SortDirection="TemplateBinding local:DataGridColumnHeaderCell.SortDirection"
IsHovered="TemplateBinding UIElement.IsMouseOver"
并将程序集 PresentationFramework.Aero2.dll 添加到 References 部分,然后 XAML 引发错误。
XML 命名空间“clr-namespace:Microsoft.Windows.Themes”中不存在标记“DataGridHeaderBorder”。第 193 行位置 14.EhLib.WPF 1 C:...Lib.WPF\Themes C:.....WPF\Themes\Generic.xaml 193 14 如果我这样写:
xmlns:theme="clr-namespace:Microsoft.Windows.Themes;assembly=PresentationFramework.Aero2"
然后错误消失,但我无法在 Windows 7 上运行该应用程序
在启动时,程序本身决定加载和使用 Aero、Aero2、Luna、Classic 或 Royale 的资源程序集。
问题: 我也可以选择所需的程序集并将其替换为字符串吗?
xmlns: theme = "clr-namespace: Microsoft.Windows.Themes; assembly =% PresentationFramework.XXX%"
最终应用程序的开发人员可以使用以下代码覆盖样式程序集: ResourceDictionary 中的来源。
<Application x:Class="EhLibTestApp.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:EhLibTestApp"
StartupUri="MainForm.xaml">
<Application.Resources>
<ResourceDictionary Source="/PresentationFramework.Classic, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, ProcessorArchitecture=MSIL;component/themes/classic.xaml" />
</Application.Resources>
</Application>
如果他会使用我的控件,那么对于DataGridHeaderBorder类的正确引用,该控件应该引用选中的样式程序集。
如何在考虑操作系统版本和 Application.Resources ResourceDictionary Source 覆盖的情况下正确执行此操作?
我希望使用 DataGridHeaderBorder 的控件看起来与标准 WFP 控件相同。 特别是 DataGrid。
DataGridHeaderBorder 使用的DataGrid 标头在不同的操作系统和设置下以自己的方式看起来,它对应于当前的Windows 主题。 如果我在我的 WPF 控件中使用 DataGridHeaderBorder,那么它看起来总是一样的,并且可能与 Windows 主题不对应。
【问题讨论】:
您是否尝试将PresentationFramework.Aero2
作为部署到 Windows 7 的应用程序的一部分包含在内?我认为它应该是向后兼容的。
我没试过,但是为什么要这样做。毕竟,我希望我的控件看起来与标准控件相同。如果程序在 Windows 7 上运行,那么我的控件应该看起来像 Windows 7 的控件。如果最终程序的开发人员重新定义了 Application.Resources.ResourceDictionary 中的样式并且标准控制器使用这些覆盖,那么我的控件也应该使用这个覆盖。
那么您的实际问题是什么?
我希望使用 DataGridHeaderBorder 的控件看起来与标准 WFP 控件相同。特别是 DataGrid。 DataGridHeaderBorder 使用的 DataGrid 标头在不同的操作系统和设置下以自己的方式看起来,它对应于当前的 Windows 主题。如果我在我的 WPF 控件中使用 DataGridHeaderBorder,那么它看起来总是一样的,并且可能与 Windows 主题不对应。
您需要为每个主题定义一个样式。
【参考方案1】:
您可以在您的主题文件夹中为每个主题定义一个ResourceDictionary
,前提是定义控件的程序集标有ThemeInfoAttribute
,并且具有docs 中描述的所有其他附加特征:
[assembly:ThemeInfoAttribute(ResourceDictionaryLocation.None, ResourceDictionaryLocation.SourceAssembly)]
然后您的资源字典将被命名为:
主题\luna.normalcolor.xaml 主题\luna.homestead.xaml 主题\luna.metallic.xaml 主题\royale.normalcolor.xaml 主题\aero.normalcolor.xaml 主题\classic.xaml如果包含控件样式的资源字典是在与控件类分开的程序集中定义的,则应将ThemeInfoAttribute
的ResourceDictionaryLocation
设置为ResourceDictionaryLocation.ExternalAssembly
,并将外部程序集命名为<YourControlAssembly>.<ThemeName>.dll
。这就是PresentationFramework.dll
所做的。这是具有此属性的市场:
[assembly:ThemeInfo(ResourceDictionaryLocation.ExternalAssembly, ResourceDictionaryLocation.None)]
并且样式定义在PresentationFramework.Aero.dll
、PresentationFramework.Classic.dll
等中
通过命名约定查找模板。除了docs,您还可以参考Ian Griffith's blog post了解更多信息。
【讨论】:
-- 我将 ThemeInfo 设置为 [assembly:ThemeInfo( ResourceDictionaryLocation.SourceAssembly, ResourceDictionaryLocation.SourceAssembly )] 以拥有通用和主题特定的资源字典 -- 然后我创建了 aero.normalcolor.xaml 和 classic.xaml我将主题特定的类转移到 aero.normalcolor.xaml 并复制到 classic.xaml。 -- 这似乎影响了某些东西,但在运行时系统似乎总是从 classic.xaml 中选择资源。所以这不能按预期工作。我只在 Windows 10 中测试过。以上是关于如何编写风格化但独立于操作系统的 WPF 控件。使用 Microsoft.Windows.Themes的主要内容,如果未能解决你的问题,请参考以下文章
如何使 WPF 应用程序在 Windows 经典风格和 Windows XP 风格中都一样?