在 Silverlight 里面建自定義控件(Templated Control),會(huì)在工程下生成一個(gè)Themes文件夾,并在其中包含一個(gè)generic.xaml 文件。這是一個(gè) ResourceDictionary 文件,所有的自定義控件的默認(rèn)樣式(Default Style)都必須放在這里。
最原始的辦法就是把所有樣式都直接寫在 generic.xaml 文件里,但如果自定義控件足夠多,generic.xaml 達(dá)到了好幾千行,管理起來當(dāng)然十分麻煩。后來在同事的推薦下,搞到兩種方法可以將各自定義控件的樣式分開管理,總算解決了這一令人頭疼的問題。
如果研究過 Silverlight Toolkit 的源代碼,會(huì)發(fā)現(xiàn)里面所有的自定義控件都有一個(gè)單獨(dú)的 xaml 文件來保存控件的默認(rèn)樣式,當(dāng)然這些文件是不起作用的。最初我以為是先用單獨(dú)的 xaml 文件來寫控件樣式,然后再拷貝到 generic.xaml 里,也就是人工同步。于是我就這么做了……最終發(fā)現(xiàn)實(shí)在是很傻很天真,人工同步比被墻的 Dropbox 還不靠譜。
后來發(fā)現(xiàn)了 MergeDefaultStyle 這個(gè)東東,才搞清楚之前原來是被耍了。
MergeDefaultStyle 就是通過給所有單獨(dú)的 xaml 文件應(yīng)用一種特殊的 Build 方法,在 Build 工程的時(shí)候,自動(dòng)把 xaml 文件的內(nèi)容整合到 generic.xaml 里去。
詳細(xì)的介紹請(qǐng)參看:http://www.jeff.wilcox.name/2009/01/default-style-task/
重點(diǎn)步驟是:
1. 拷貝里面的代碼或者直接下載MergeDefaultStyle.dll。
2. 在VS里面Unload你的工程,然后編輯工程文件,或者直接用文本編輯器打開csproj文件。
3. 在最后加上下面這段代碼:
<UsingTask
TaskName="Engineering.Build.Tasks.MergeDefaultStylesTask"
AssemblyFile="$(EngineeringResources)\Engineering.Build.dll" />
注意:AssemblyFile 的值是你放MergeDefaultStyle.dll的位置,可以用相對(duì)路徑。
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. 選擇有默認(rèn)樣式的單獨(dú)的 xaml ,在屬性窗口的 Build Action 里面選擇 DefaultStyle 。
7. 編譯整個(gè)工程,再打開 generic.xaml 文件,你會(huì)發(fā)現(xiàn) xaml 文件里的內(nèi)容已經(jīng)拷到 generic.xaml 里面了。
這一方法適用于 Silverlight 2\3\4 。
上面的方法可謂是一勞永逸了,但多少有點(diǎn)不官方。而且其實(shí)還是 generic.xaml 掌控全局,一旦一個(gè) xaml 文件出了紕漏,會(huì)影響所有的控件跟著出錯(cuò)。這樣排查起來也麻煩的很。
于是在 Silverlight 3 里就出來了一個(gè)更簡(jiǎn)單更官方的方法。如前所述,generic.xaml 文件包含了一個(gè)ResourceDictionary,而 Silverlight 3 里面的 ResourceDictionary 多了一個(gè) MergedDictionaries 的屬性,可以把其他 ResourceDictionary 通過資源路徑整合到一個(gè) ResourceDicionary 里面。
其實(shí)新建一個(gè) Silverlight 導(dǎo)航應(yīng)用時(shí),就可以在 App.xaml 里面看到這一屬性的應(yīng)用。需要注意的是,在 App.xaml 里面是可以用相對(duì)路徑的,而在 generic.xaml 里面,不可以用相對(duì)路徑,而應(yīng)當(dāng)用 "/AssemblyName;component/path”的方法說明文件路徑。
比如你的工程的 AssemblyName 是 Slippor.Controls,而 xaml 的路徑是 CustomControl 文件夾下的CustomControl.xaml 。則應(yīng)該在 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 。
聯(lián)系客服