代码改变世界

【原】Silverlight 自定义控件模板管理

  拖鞋不脱  阅读(2769)  评论(3编辑  收藏  举报

在 Silverlight 里面建自定义控件(Templated Control),会在工程下生成一个Themes文件夹,并在其中包含一个generic.xaml 文件。这是一个 ResourceDictionary 文件,所有的自定义控件的默认样式(Default Style)都必须放在这里。

最原始的办法就是把所有样式都直接写在 generic.xaml 文件里,但如果自定义控件足够多,generic.xaml 达到了好几千行,管理起来当然十分麻烦。后来在同事的推荐下,搞到两种方法可以将各自定义控件的样式分开管理,总算解决了这一令人头疼的问题。

MergeDefaultStyle 法

如果研究过 Silverlight Toolkit 的源代码,会发现里面所有的自定义控件都有一个单独的 xaml 文件来保存控件的默认样式,当然这些文件是不起作用的。最初我以为是先用单独的 xaml 文件来写控件样式,然后再拷贝到 generic.xaml 里,也就是人工同步。于是我就这么做了……最终发现实在是很傻很天真,人工同步比被墙的 Dropbox 还不靠谱。

后来发现了 MergeDefaultStyle 这个东东,才搞清楚之前原来是被耍了。

MergeDefaultStyle 就是通过给所有单独的 xaml 文件应用一种特殊的 Build 方法,在 Build 工程的时候,自动把 xaml 文件的内容整合到 generic.xaml 里去。

详细的介绍请参看:http://www.jeff.wilcox.name/2009/01/default-style-task/

重点步骤是:

1. 拷贝里面的代码或者直接下载MergeDefaultStyle.dll

2. 在VS里面Unload你的工程,然后编辑工程文件,或者直接用文本编辑器打开csproj文件。

3. 在最后加上下面这段代码:

<UsingTask
  TaskName="Engineering.Build.Tasks.MergeDefaultStylesTask"
  AssemblyFile="$(EngineeringResources)\Engineering.Build.dll" />

注意:AssemblyFile 的值是你放MergeDefaultStyle.dll的位置,可以用相对路径。

4. 再在后面加上这一段代码:

<!-- Add "DefaultStyle" as a Build Action in Visual Studio -->
<ItemGroup Condition="'$(BuildingInsideVisualStudio)'=='true'">
  <AvailableItemName Include="DefaultStyle" />
</ItemGroup>
<!--
Merge the default styles of controls (only if any of the DefaultStyle files is
more recent than the project's generic.xaml file) before compilation
dependencies are processed.
-->
<PropertyGroup>
  <PrepareResourcesDependsOn>
    MergeDefaultStyles;
    $(PrepareResourcesDependsOn);
  </PrepareResourcesDependsOn>
</PropertyGroup>
<Target
  Name="MergeDefaultStyles"
  Inputs="@(DefaultStyle)"
  Outputs="$(MSBuildProjectDirectory)\generic.xaml">
  <MergeDefaultStylesTask
    DefaultStyles="@(DefaultStyle)"
    ProjectDirectory="$(MSBuildProjectDirectory)" />
</Target>
<!--
Touch DefaultStyles on Rebuild to force generation of generic.xaml.
-->
<PropertyGroup>
  <RebuildDependsOn>
    TouchDefaultStyles;
    $(RebuildDependsOn);
  </RebuildDependsOn>
</PropertyGroup>
<Target Name="TouchDefaultStyles">
  <Touch Files="@(DefaultStyle)" ForceTouch="true" />
</Target>

5. 重新 Load 你的工程。

6. 选择有默认样式的单独的 xaml ,在属性窗口的 Build Action 里面选择 DefaultStyle 。

7. 编译整个工程,再打开 generic.xaml 文件,你会发现 xaml 文件里的内容已经拷到 generic.xaml 里面了。

这一方法适用于 Silverlight 2\3\4

MergedDictionary 法

上面的方法可谓是一劳永逸了,但多少有点不官方。而且其实还是 generic.xaml 掌控全局,一旦一个 xaml 文件出了纰漏,会影响所有的控件跟着出错。这样排查起来也麻烦的很。

于是在 Silverlight 3 里就出来了一个更简单更官方的方法。如前所述,generic.xaml 文件包含了一个ResourceDictionary,而 Silverlight 3 里面的 ResourceDictionary 多了一个 MergedDictionaries 的属性,可以把其他 ResourceDictionary 通过资源路径整合到一个 ResourceDicionary 里面。

其实新建一个 Silverlight 导航应用时,就可以在 App.xaml 里面看到这一属性的应用。需要注意的是,在 App.xaml 里面是可以用相对路径的,而在 generic.xaml 里面,不可以用相对路径,而应当用 "/AssemblyName;component/path”的方法说明文件路径。

比如你的工程的 AssemblyName 是 Slippor.Controls,而 xaml 的路径是 CustomControl 文件夹下的CustomControl.xaml 。则应该在 generic.xaml 里面如下写:

<ResourceDictionary xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
  <ResourceDictionary.MergedDictionaries>
    <ResourceDictionary Source="/Slippor.Controls;component/CustomControl/CustomControl.xaml"/>
  </ResourceDictionary.MergedDictionaries>
</ResourceDictionary>

这一方法适用于 Silverlight 3\4 。

编辑推荐:
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
阅读排行:
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
· DeepSeek如何颠覆传统软件测试?测试工程师会被淘汰吗?
历史上的今天:
2008-08-24 【译】提高网站访问速度的34条军规(4-6)
点击右上角即可分享
微信分享提示