WPF 的样式浏览器






4.82/5 (9投票s)
用于预览 WPF 中 XAML 样式的应用程序。
引言
在本文中,我将向您展示一个可以帮助您浏览 XAML 样式的简单应用程序。您可以从上面的链接下载源代码。
背景
我相信每个 WPF 开发人员都遇到过这样的问题:大量的样式……大量的图像、画笔、不同的文本框和文本块。有时很难找到所需的资源键。这个问题在有很多自定义控件的大型 WPF 项目中经常遇到。当有多个开发人员时——这会更加困难!但对于某些情况,有一个相当简单的解决方案。本文介绍的应用程序可以帮助您简化此过程。使用 StyleBrowser,您可以选择一些 XAML 并“查看”其内部。该应用程序将向您显示指定 XAML 文件中存储的所有样式、图像和画笔。
此外,当您想使用之前创建但不记得 XAML 文件中确切内容的样式时,也可以使用此应用程序。只需打开 XAML,找到所需的样式,然后使用它!
使用应用程序
打开应用程序后,您将看到以下屏幕
按“选择 XAML”,您的桌面上将出现一个打开对话框。选择包含样式的 XAML 文件,然后按确定。如果 XAML 已解析,您将看到类似以下内容
在应用程序的中间,有一个 TabControl
,包含多个选项卡。每个选项卡都是 XAML 中某些样式的一个组。在截图中,打开了“Buttons”选项卡,您可以看到 XAML 中的按钮。“Sample content”会自动添加到具有 Content
属性的每个控件中。使用反射进行检测。右侧是样式键及其类名。所有样式都按字母顺序排序。
此外,还有两个有用的功能可以帮助您。您可以选择背景,因为有些样式是白色的,有些是黑色的……有些是黑白色的 :)。目前,只有三种预定义颜色:黑色、白色和灰色。我认为将来会有类似颜色选择器之类的东西。
第二个功能是搜索。只需在搜索文本框中键入任何单词,您将只看到与搜索文本匹配的样式。颜色和搜索显示在下图
最后一个有趣的有用功能是您可以查看 XAML。只需点击您想查看的样式右侧的“XAML”按钮。但是这个功能有一个缺点:它会显示带有完全限定类名和 XML 命名空间的 XAML。但是简单的 XAML 看起来不错,并且可能很有用。
代码截图
让我们简要浏览一下代码,看看它是如何工作的。一开始,使用 OpenDialog 选择文件。
要解析 XAML,我只需使用以下代码
XamlReader reader = new XamlReader();
FileStream stream = new FileStream(dlg.FileName, FileMode.Open);
Uri uri = new Uri((new FileInfo(dlg.FileName)).Directory.FullName + "\\");
object xaml = reader.LoadAsync(stream, new ParserContext() { BaseUri = uri });
我们必须在此处指定 BaseUri
,以便解析器能够处理相对路径到图像或其他文件(如果它们存在于 XAML 中)。
此代码有一个缺点。如果标签无法解析,XAML 将根本不会被读取。所以我们有这样的限制:XAML 只能包含源编译的 .NET 版本中默认定义的命名空间。我的解决方案使用 .NET 4.0。
另外,您应该小心图像路径。
下一步是用加载的样式填充当前窗口的资源。我们需要这样做,因为有些样式会使用该 XAML 中的其他样式。如果我们不将 XAML 复制到资源中,则引用的 XAML 将不会被加载。
this.Resources.Clear();
if (xaml is ResourceDictionary)
{
foreach (DictionaryEntry item in (xaml as ResourceDictionary))
{
this.Resources.Add(item.Key, item.Value);
entries.Add(item);
}
}
目前,此代码还有另一个问题:有时主窗口中在其资源中有其样式的控件会改变其外观,即使该控件不在预览区域中。我将在将来修复这个问题。
所以我们有样式、画笔和图像的集合。我们可以用它做任何事情。排序、分组等。在我的应用程序中,样式按字母顺序排序。
下一个任务是遍历集合中的每个项目,并在相关的选项卡控件中创建预览。
foreach (var item in list.OrderBy(e => e.Key.ToString()))
{
StyleItem styleItem = null;
DictionaryEntry entry = (DictionaryEntry)item;
if (entry.Value is Style)
{
Style style = entry.Value as Style;
Type type = style.TargetType;
object obj = Activator.CreateInstance(type);
if (obj is AnimationTimeline) continue;
styleItem = new StyleItem(obj as FrameworkElement,
style, type, entry.Key.ToString());
if (type == typeof(Button) || type == typeof(ToggleButton))
{
buttonsPanel.Children.Add(styleItem);
}
StyleItem
是一个表示样式预览的自定义控件。每个 DictionaryEntry
都有一个 Key
和 Value
(就像字典一样 :))。Key
是 XAML 中的 x:Key
属性。Value
是 XML 元素的内容。
我们必须检查值的类型,因为例如,如果当前项目是图像,您就不能应用 Style
属性。此外,我们需要跳过任何动画,因为无法为动画创建通用预览。如果项目是画笔或图像,我只需将预览的背景设置为图像或画笔。
如果项目是 Style
,有三行重要代码,它们提取样式、对象类型,并创建提取类型的实例。
Style style = entry.Value as Style;
Type type = style.TargetType;
object obj = Activator.CreateInstance(type);
然后 StyleItem
使用此信息来创建 TabControl
中相关的预览项。
另一个有趣的事情是如何创建预览 XAML 文本。
string xaml;
try
{
xaml = XamlWriter.Save(entry.Value).Replace(">", ">\n").NormalizeXaml();
}
catch { xaml = "XAML cannot be parsed"; }
为什么在这里使用 Replace
方法?因为 Save()
返回一个不带换行符的字符串。所以我决定在每个“>”之后插入一个换行符。
此外,还有一个 String
的扩展方法:NormalizeXaml()
。
此方法根据 XML 中的深度在每行开头插入空格。我不确定是否应该在这篇文章中展示此方法的实现。
限制和未来
目前,此应用程序存在一些问题。但是,如果您觉得它有用,请告诉我。如果开发人员喜欢这个应用程序的功能,我将继续努力并添加新的有用功能并修复当前问题。
将来,我将
- 跳过有错误的样式。
- 添加包含资源的 DLL。
- 添加不同 XAML 的功能。例如,如果一个 XAML 引用了另一个 XAML 中定义的样式。
- 添加颜色选择器来选择自定义背景颜色。
- 清理 XAML 源查看器中的命名空间和完全限定路径。
- 创建一个更智能的对象创建器。例如:为菜单、选项卡控件和其他具有复杂内容的控件使用预定义的 Content 模板。
- 使预览区域可调整大小。例如,一个小的文本需要一个小的矩形,而滑块或图像有时需要一个巨大的区域。
- 也许您会告诉我一些可以包含的有趣功能。