Welcome

首页 / 软件开发 / Silverlight / Silverlight开发中的疑难杂症-如何自动合并控件的默认样式

Silverlight开发中的疑难杂症-如何自动合并控件的默认样式2011-04-13 博客园 yingql在WPF中开发自定义控件时,可以将控件的默认样式放在以“<控件类型 >.Generic.xaml”的形式命名的资源文件中,从而分离各个自定义控件的默认样式的定义 ,减少单个Generic.xaml文件的复杂度。

但是在Silverlight控件开发时,却发现无法采用上面的方法来实现这一效果,尝试了许 久都没有找到其他的办法实现这一效果。郁闷之中,突然想起看一下Silverlight Toolkit中 是如何解决这一问题的,结果惊讶的发现它也是将所有的默认样式都堆积在了Generic.xaml 一个文件当中,感觉相当的不可思议。但是,仔细一看,发现在Generic.xaml文件的开头有 如下的一段话:

XML

<!--
// WARNING:
//
// This XAML was automatically generated by merging the individual default
// styles. Changes to this file may cause incorrect behavior and will be lost
// if the XAML is regenerated.
-->

这让我又感觉到了希望,于是祭出神器“谷歌”,以上面的话中的一部分为关键字,进行 了搜索,果然让我找到了相关的文章,原文地址如下: http://www.jeff.wilcox.name/2009/01/default-style-task/ ,在这里面介绍了如何通过 MSBuild的自定义任务来实现将项目中的独立的控件样式在编译阶段合并到一起,文章里面包 含了详细的解说和代码,只要按照提示一步步来做就可以了。

如果您对MSBuild比较熟悉,那么按照他的提示,应该就能顺利的完成这一个功能。但是 很不幸,我对于MSBuild一窍不通,于是第一遍下来,编译后,什么事情都没有发生。如果你 跟我一样对MSBuild不甚了解,但是又想要能够得到这个非常有用的特性,那么希望下面的介 绍能够对你有所帮助。关于MSBuild的介绍及相关知识,有兴趣的朋友可以参见MSDN中的相关 文章,链接如下:http://msdn.microsoft.com/zh-cn/library/ms171452.aspx 我在这里只 介绍如何简单的实现这一功能。

首先,新建一个类库项目,在里面添加文章中提到的两个类,代码如下:

MergeDefaultStylesTask

1 // (c) Copyright Microsoft Corporation.
2 // This source is subject to the Microsoft Public License (Ms-PL).
3 // Please see http://go.microsoft.com/fwlink/?LinkID=131993 for details.
4 // All other rights reserved.
5
6 using System;
7 using System.Collections.Generic;
8 using System.Diagnostics.CodeAnalysis;
9 using System.IO;
10 using System.Text;
11 using Microsoft.Build.Framework;
12 using Microsoft.Build.Utilities;
13
14 namespace Engineering.Build.Tasks
15 {
16 /// <summary>
17 /// Build task to automatically merge the default styles for controls into
18 /// a single generic.xaml file.
19 /// </summary>
20 public class MergeDefaultStylesTask : Task
21 {
22 /// <summary>
23 /// Gets or sets the root directory of the project where the
24 /// generic.xaml file resides.
25 /// </summary>
26 [Required]
27 public string ProjectDirectory { get; set; }
28
29 /// <summary>
30 /// Gets or sets the project items marked with the "DefaultStyle" build
31 /// action.
32 /// </summary>
33 [Required]
34 public ITaskItem[] DefaultStyles { get; set; }
35
36 /// <summary>
37 /// Initializes a new instance of the MergeDefaultStylesTask class.
38 /// </summary>
39 public MergeDefaultStylesTask()
40 {
41 }
42
43 /// <summary>
44 /// Merge the project items marked with the "DefaultStyle" build action
45 /// into a single generic.xaml file.
46 /// </summary>
47 /// <returns>
48 /// A value indicating whether or not the task succeeded.
49 /// </returns>
50 [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "Task should not throw exceptions.")]
51 public override bool Execute()
52 {
53 Log.LogMessage (MessageImportance.Low, "Merging default styles into generic.xaml.");
54
55 // Get the original generic.xaml
56 string originalPath = Path.Combine(ProjectDirectory, Path.Combine("themes", "generic.xaml"));
57 if (!File.Exists(originalPath))
58 {
59 Log.LogError("{0} does not exist!", originalPath);
60 return false;
61 }
62 Log.LogMessage(MessageImportance.Low, "Found original generic.xaml at {0}.", originalPath);
63 string original = null;
64 Encoding encoding = Encoding.Default;
65 try
66 {
67 using (StreamReader reader = new StreamReader(File.Open (originalPath, FileMode.Open, FileAccess.Read)))
68 {
69 original = reader.ReadToEnd();
70 encoding = reader.CurrentEncoding;
71 }
72 }
73 catch (Exception ex)
74 {
75 Log.LogErrorFromException(ex);
76 return false;
77 }
78
79 // Create the merged generic.xaml
80 List<DefaultStyle> styles = new List<DefaultStyle>();
81 foreach (ITaskItem item in DefaultStyles)
82 {
83 string path = Path.Combine(ProjectDirectory, item.ItemSpec);
84 if (!File.Exists(path))
85 {
86 Log.LogWarning("Ignoring missing DefaultStyle {0}.", path);
87 continue;
88 }
89
90 try
91 {
92 Log.LogMessage(MessageImportance.Low, "Processing file {0}.", item.ItemSpec);
93 styles.Add(DefaultStyle.Load(path));
94 }
95 catch (Exception ex)
96 {
97 Log.LogErrorFromException(ex);
98 }
99 }
100 string merged = null;
101 try
102 {
103 merged = DefaultStyle.Merge (styles).GenerateXaml();
104 }
105 catch (InvalidOperationException ex)
106 {
107 Log.LogErrorFromException(ex);
108 return false;
109 }
110
111 // Write the new generic.xaml
112 if (original != merged)
113 {
114 Log.LogMessage (MessageImportance.Low, "Writing merged generic.xaml.");
115
116 try
117 {
118 // Could interact with the source control system / TFS here
119 File.SetAttributes(originalPath, FileAttributes.Normal);
120 Log.LogMessage("Removed any read-only flag for generic.xaml.");
121
122 File.WriteAllText(originalPath, merged, encoding);
123 Log.LogMessage("Successfully merged generic.xaml.");
124 }
125 catch (Exception ex)
126 {
127 Log.LogErrorFromException(ex);
128 return false;
129 }
130 }
131 else
132 {
133 Log.LogMessage ("Existing generic.xaml was up to date.");
134 }
135
136 return true;
137 }
138 }
139 }
140