当前位置: 首页 > 图灵资讯 > 技术篇> WPF控件模板查看

WPF控件模板查看

来源:图灵教育
时间:2023-05-21 09:17:28

介绍我查看WPF控件模板的常用方法。包括创建控件并显示查看、反编译查看BAML资源和查看源代码。

背景

在使用WPF的过程中,通常需要定制控制器的外观。此时,有必要查看其原始样式或模板以供参考。这可以减少许多工作,只修改所需的部分,并避免在修改模板或样式后失去某些功能。以下是我常用的方法。

创建控件并显示检查模板的原理

您可以手动创建控件,然后使用XamlWriter保存模板来查看控件的当前模板。如果您对此感兴趣,请查看WPF编程宝典——C#2010版》(《Pro WPF in C# 2010》)17.2.2 分析控件的相关部分。

简单修改后,上述方法也可用于查看风格或第三方控件的模板。例如,我用这种方法查看了Devexpress中图表控件的模板。

不足
  • XAML代码保存在XamlWriter类中有些冗余和不直观,因为它总是使用属性元素语法而不是特性语法。
  • 对于某些类型,无法正确检查。例如,缺乏默认构造函数的控件(在第三方控件中更常见,如Devexpress)。另一个例子是一些不能直接显示在窗口中的类型(Tolltip、contextmenu等)
示例代码

基于WPF编程宝典的基础,我自己改进了一个控件检查工具。具有以下功能:

  • 可查看控件模板和样式。
  • 支持检查第三方控件
  • 支持语法亮点

效果如下:

WPF控件模板查看_控件

在实际显示控件之前,模板是空的。因此,在代码中使用了一个小技巧,将控件放入一个1像素宽高的窗口中,以便检查控件模板。

博客园:

WPFTemplateViewer

反编译查看BAML资源原理

一般来说,控件提供商在资源字典中为控件准备了样式和模板。资源字典存储在控件所在的程序集或外部程序集中。必要时,可以使用C#反编译工具(如ILSpy)、dotPeek)查看BAML资源。

主题

在WPF3.0中,WPF为自己的控件准备了4套主题,即Aero、Classic、Luna、Royale。主题资源字典文件名及相应含义如下:

WPF控件模板查看_控件_02

Aero2和Aerolite在WPF4.0中又增加了两套主题。在Win8及以上版本的系统中,Framework会自动将Aero主题转换为Aero2主题,可以通过反编译PresentationFramework来证实。Aerolite没有查询权威声明,网上有人说是用于Windows的 Server 2012。

WPF控件模板查看_控件_03

对上述代码进行整理,以确定当前使用的主题名称和颜色 。

public static Tuple<string, string> GetThemeInfo()        {            StringBuilder themePathBuff = new StringBuilder(260);            StringBuilder themeColorBuff = new StringBuilder(260);            if (GetCurrentThemeName(themePathBuff, themePathBuff.Capacity, themeColorBuff, themeColorBuff.Capacity, null, 0) == 0)            {                string themeName = System.IO.Path.GetFileNameWithoutExtension(themePathBuff.ToString());                string themeColor = themeColorBuff.ToString();                if (string.Compare(themeName, "aero", StringComparison.OrdinalIgnoreCase) == 0                    && Environment.OSVersion.Version >= new Version(6, 2))                {                    themeName = “Aero2”;                }                return new Tuple<string, string>(themeName, themeColor);            }            else            {                return new Tuple<string, string>(string.Empty, string.Empty);            }        }        [DllImport("uxtheme.dll", CharSet = CharSet.Unicode, EntryPoint = "GetCurrentThemeName")]        private static extern int GetCurrentThemeName(StringBuilder pszThemeFileName, int dwMaxNameChars, StringBuilder pszColorBuff, int cchMaxColorChars, StringBuilder pszSizeBuff, int cchMaxSizeChars);

查找控件样式顺序

Framework在寻找控件样式时,首先要尝试寻找具体主题名的资源,如果找不到,那就去寻找Classic.xaml。最后,寻找常规资源(generic.xaml)。

确定BAML资源所在的程序集

控件样式位于定义程序集还是外部程序集,可以通过反编译查看控件定义程序集元数据的themeinfoattribute特性来确定。themeinfoatribute结构函数包括两个参数,前者指定特定主题资源的位置,后者指定常规资源的位置。

外部程序集

WPF自带的控件通过ILSpy反编译查看Presentationframework程序集元数据,发现Themeinfratibute特性信息如下:

ThemeInfo(ResourceDictionaryLocation.ExternalAssembly, ResourceDictionaryLocation.None)

WPF控件模板查看_控件_04

表明控件没有常规资源,控件的主题集中在外部程序上。

每个主题对应的DLL名称是PresentationFramework.主题名称,如Aero对应Presentationframework.Aero.dll、Clasic对应Presentationframework.Classic.dll。

定义程序集

例如,常用的Devexpress,通过ILSpy反编译查看Devexpress.Xpf.Core。

WPF控制模板查看_控制_05

表明控件没有特定的主题资源,只有常规资源,位于当前程序集中。

反编译查看BAML资源

以ILSpy为例,说明如何查看BAML资源。

  1. 用ILSpy打开程序集
  2. 展开程序集
  3. 展开程序集资源
  4. 展开(程序集名称).g.resources
  5. 根据上述命名规则,确定BAML资源文件。XAML,无论是特定的主题资源还是常规资源,都位于Themes文件夹下。
  6. 在BAML资源文件中找到控制样式。值得注意的是,资源字典可以嵌套在包含资源字典中,可能需要仔细分析和多次搜索来定位所需的控制样式。

下图为PresentationFramework特定主题BAML

WPF控件模板查看_程序集_06

下图为Devexpresss.Xpf.Core.常规资源BAMLv15.2,可见嵌套包含其他资源字典。

WPF控件模板查看_WPF_07

不足

在某些情况下,它将更加复杂,需要仔细分析。PresentationFramework中的控件仍然很容易找到,我通常通过x:Type (控件名称) 直接查找。

查看源码原理

这个标题只是为了整洁。有代码,还说什么,不仅知道为什么,还知道为什么。

不足

该方法仅适用于开源控件。如Extendeded。 WPF Toolkit。

好消息是微软也开源了WPF,风格相关代码位于Microsoft.DotNet.Wpf/src/Themes/XAML目录。相同控件的所有主题样式都在相应控件的XMAL文件中。

参考链接控件创建概述What is the theme name for a WPF application on Windows 8?