Silverlight开发中的疑难杂症-控件设计篇-如何自动合并控件的默认样式

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 
DefaultStyle
  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.Globalization;
  9  using  System.IO;
 10  using  System.Linq;
 11  using  System.Xml.Linq;
 12 
 13  namespace  Engineering.Build
 14  {
 15       ///   <summary>
 16       ///  DefaultStyle represents the XAML of an individual Control's default
 17       ///  style (in particular its ControlTemplate) which can be merged with other
 18       ///  default styles).  The XAML must have a ResourceDictionary as its root
 19       ///  element and be marked with a DefaultStyle build action in Visual Studio.
 20       ///   </summary>
 21       public   partial   class  DefaultStyle
 22      {
 23           ///   <summary>
 24           ///  Root element of both the default styles and the merged generic.xaml.
 25           ///   </summary>
 26           private   const   string  RootElement  =   " ResourceDictionary " ;
 27 
 28           ///   <summary>
 29           ///  Gets or sets the file path of the default style.
 30           ///   </summary>
 31           public   string  DefaultStylePath {  get set ; }
 32 
 33           ///   <summary>
 34           ///  Gets the namespaces imposed on the root element of a default style
 35           ///  (including explicitly declared namespaces as well as those inherited
 36           ///  from the root ResourceDictionary element).
 37           ///   </summary>
 38           public  SortedDictionary < string string >  Namespaces {  get private   set ; }
 39 
 40           ///   <summary>
 41           ///  Gets the elements in the XAML that include both styles and shared
 42           ///  resources.
 43           ///   </summary>
 44           public  SortedDictionary < string , XElement >  Resources {  get private   set ; }
 45 
 46           ///   <summary>
 47           ///  Gets or sets the history tracking which resources originated from
 48           ///  which files.
 49           ///   </summary>
 50           private  Dictionary < string string >  MergeHistory {  get set ; }
 51 
 52           ///   <summary>
 53           ///  Initializes a new instance of the DefaultStyle class.
 54           ///   </summary>
 55           protected  DefaultStyle()
 56          {
 57              Namespaces  =   new  SortedDictionary < string string > (StringComparer.OrdinalIgnoreCase);
 58              Resources  =   new  SortedDictionary < string , XElement > (StringComparer.OrdinalIgnoreCase);
 59              MergeHistory  =   new  Dictionary < string string > (StringComparer.OrdinalIgnoreCase);
 60          }
 61 
 62           ///   <summary>
 63           ///  Load a DefaultStyle from the a project item.
 64           ///   </summary>
 65           ///   <param name="path">
 66           ///  Path of the default style which is used for reporting errors.
 67           ///   </param>
 68           ///   <returns> The DefaultStyle. </returns>
 69           public   static  DefaultStyle Load( string  path)
 70          {
 71              DefaultStyle style  =   new  DefaultStyle();
 72              style.DefaultStylePath  =  path;
 73 
 74               string  xaml  =  File.ReadAllText(path);
 75              XElement root  =  XElement.Parse(xaml, LoadOptions.PreserveWhitespace);
 76               if  (root.Name.LocalName  ==  RootElement)
 77              {
 78                   //  Get the namespaces
 79                   foreach  (XAttribute attribute  in  root.Attributes())
 80                  {
 81                       if  (attribute.Name.LocalName  ==   " xmlns " )
 82                      {
 83                          style.Namespaces.Add( "" , attribute.Value);
 84                      }
 85                       else   if  (attribute.Name.NamespaceName  ==  XNamespace.Xmlns.NamespaceName)
 86                      {
 87                          style.Namespaces.Add(attribute.Name.LocalName, attribute.Value);
 88                      }
 89                  }
 90 
 91                   //  Get the styles and shared resources
 92                   foreach  (XElement element  in  root.Elements())
 93                  {
 94                       string  name  =  (element.Name.LocalName  ==   " Style " ?
 95                          GetAttribute(element,  " TargetType " " Key " " Name " ) :
 96                          GetAttribute(element,  " Key " " Name " );
 97                       if  (style.Resources.ContainsKey(name))
 98                      {
 99                           throw   new  InvalidOperationException( string .Format(
100                              CultureInfo.InvariantCulture,
101                               " Resource \ " { 0 }\ "  is used multiple times in {1} (possibly as a Key, Name, or TargetType)! " ,
102                              name,
103                              path));
104                      }
105                      style.Resources.Add(name, element);
106                      style.MergeHistory[name]  =  path;
107                  }
108              }
109 
110               return  style;
111          }
112 
113           ///   <summary>
114           ///  Get the value of the first attribute that is defined.
115           ///   </summary>
116           ///   <param name="element"> Element with the attributes defined. </param>
117           ///   <param name="attributes">
118           ///  Local names of the attributes to find.
119           ///   </param>
120           ///   <returns> Value of the first attribute found. </returns>
121           private   static   string  GetAttribute(XElement element,  params   string [] attributes)
122          {
123               foreach  ( string  name  in  attributes)
124              {
125                   string  value  =
126                      (from a  in  element.Attributes()
127                        where  a.Name.LocalName  ==  name
128                       select a.Value)
129                       .FirstOrDefault();
130                   if  (name  !=   null )
131                  {
132                       return  value;
133                  }
134              }
135               return   "" ;
136          }
137 
138           ///   <summary>
139           ///  Merge a sequence of DefaultStyles into a single style.
140           ///   </summary>
141           ///   <param name="styles"> Sequence of DefaultStyles. </param>
142           ///   <returns> Merged DefaultStyle. </returns>
143           public   static  DefaultStyle Merge(IEnumerable < DefaultStyle >  styles)
144          {
145              DefaultStyle combined  =   new  DefaultStyle();
146               if  (styles  !=   null )
147              {
148                   foreach  (DefaultStyle style  in  styles)
149                  {
150                      combined.Merge(style);
151                  }
152              }
153               return  combined;
154          }
155 
156           ///   <summary>
157           ///  Merge with another DefaultStyle.
158           ///   </summary>
159           ///   <param name="other"> Other DefaultStyle to merge. </param>
160           private   void  Merge(DefaultStyle other)
161          {
162               //  Merge or lower namespaces
163               foreach  (KeyValuePair < string string >  ns  in  other.Namespaces)
164              {
165                   string  value  =   null ;
166                   if  ( ! Namespaces.TryGetValue(ns.Key,  out  value))
167                  {
168                      Namespaces.Add(ns.Key, ns.Value);
169                  }
170                   else   if  (value  !=  ns.Value)
171                  {
172                      other.LowerNamespace(ns.Key);
173                  }
174              }
175 
176               //  Merge the resources
177               foreach  (KeyValuePair < string , XElement >  resource  in  other.Resources)
178              {
179                   if  (Resources.ContainsKey(resource.Key))
180                  {
181                       throw   new  InvalidOperationException( string .Format(
182                          CultureInfo.InvariantCulture,
183                           " Resource \ " { 0 }\ "  is used by both {1} and {2}! " ,
184                          resource.Key,
185                          MergeHistory[resource.Key],
186                          other.DefaultStylePath));
187                  }
188                  Resources[resource.Key]  =  resource.Value;
189                  MergeHistory[resource.Key]  =  other.DefaultStylePath;
190              }
191          }
192 
193           ///   <summary>
194           ///  Lower a namespace from the root ResourceDictionary to its child
195           ///  resources.
196           ///   </summary>
197           ///   <param name="prefix"> Prefix of the namespace to lower. </param>
198           private   void  LowerNamespace( string  prefix)
199          {
200               //  Get the value of the namespace
201               string  @namespace;
202               if  ( ! Namespaces.TryGetValue(prefix,  out  @namespace))
203              {
204                   return ;
205              }
206 
207               //  Push the value into each resource
208               foreach  (KeyValuePair < string , XElement >  resource  in  Resources)
209              {
210                   //  Don't push the value down if it was overridden locally or if
211                   //  it's the default namespace (as it will be lowered
212                   //  automatically)
213                   if  (((from e  in  resource.Value.Attributes()
214                         where  e.Name.LocalName  ==  prefix
215                        select e).Count()  ==   0 &&
216                       ! string .IsNullOrEmpty(prefix))
217                  {
218                      resource.Value.Add( new  XAttribute(XName.Get(prefix, XNamespace.Xmlns.NamespaceName), @namespace));
219                  }
220              }
221          }
222 
223           ///   <summary>
224           ///  Generate the XAML markup for the default style.
225           ///   </summary>
226           ///   <returns> Generated XAML markup. </returns>
227           public   string  GenerateXaml()
228          {
229               //  Create the ResourceDictionary
230               string  defaultNamespace  =  XNamespace.Xml.NamespaceName;
231              Namespaces.TryGetValue( "" out  defaultNamespace);
232              XElement resources  =   new  XElement(XName.Get(RootElement, defaultNamespace));
233 
234               //  Add the shared namespaces
235               foreach  (KeyValuePair < string string >  @namespace  in  Namespaces)
236              {
237                   //  The default namespace will be added automatically
238                   if  ( string .IsNullOrEmpty(@namespace.Key))
239                  {
240                       continue ;
241                  }
242                  resources.Add( new  XAttribute(
243                      XName.Get(@namespace.Key, XNamespace.Xmlns.NamespaceName),
244                      @namespace.Value));
245              }
246 
247               //  Add the resources
248               foreach  (KeyValuePair < string , XElement >  element  in  Resources)
249              {
250                  resources.Add(
251                       new  XText(Environment.NewLine  +  Environment.NewLine  +   "      " ),
252                       new  XComment( "    "   +  element.Key  +   "    " ),
253                       new  XText(Environment.NewLine  +   "      " ),
254                      element.Value);
255              }
256 
257              resources.Add( new  XText(Environment.NewLine  +  Environment.NewLine));
258 
259               //  Create the document
260              XDocument document  =   new  XDocument(
261                   //  TODO: Pull this copyright header from some shared location
262                   new  XComment(Environment.NewLine  +
263                       " // (c) Copyright Microsoft Corporation. "   +  Environment.NewLine  +
264                       " // This source is subject to the Microsoft Public License (Ms-PL). "   +  Environment.NewLine  +
265                       " // Please see http://go.microsoft.com/fwlink/?LinkID=131993 for details. "   +  Environment.NewLine  +
266                       " // All other rights reserved. "   +  Environment.NewLine),
267                   new  XText(Environment.NewLine  +  Environment.NewLine),
268                   new  XComment(Environment.NewLine  +
269                       " // WARNING: "   +  Environment.NewLine  +
270                       " //  "   +  Environment.NewLine  +
271                       " // This XAML was automatically generated by merging the individual default "   +  Environment.NewLine  +
272                       " // styles.  Changes to this file may cause incorrect behavior and will be lost "   +  Environment.NewLine  +
273                       " // if the XAML is regenerated. "   +  Environment.NewLine),
274                   new  XText(Environment.NewLine  +  Environment.NewLine),
275                  resources);
276 
277               return  document.ToString();
278          }
279 
280           ///   <summary>
281           ///  Generate the XAML markup for the default style.
282           ///   </summary>
283           ///   <returns> Generated XAML markup. </returns>
284           public   override   string  ToString()
285          {
286               return  GenerateXaml();
287          }
288      }
289  }
290 

 在实际操作中,发现当我定义了两个Button的自定义样式,他们的TargetType都是Button,但是x:Key不同,可是最后生成时还是发生了错误,提示重复。检查了代码,感觉以下两个方法有些问题,所以进行了修改,改为按照keynametargertype的顺序进行键的取值,而不是先判断targertype,相关代码如下,修改部分用红色标出:

原文代码
 1  public   static  DefaultStyle Load( string  path)
 2          {
 3              DefaultStyle style  =   new  DefaultStyle();
 4              style.DefaultStylePath  =  path;
 5 
 6               string  xaml  =  File.ReadAllText(path);
 7              XElement root  =  XElement.Parse(xaml, LoadOptions.PreserveWhitespace);
 8               if  (root.Name.LocalName  ==  RootElement)
 9              {
10                   //  Get the namespaces
11                   foreach  (XAttribute attribute  in  root.Attributes())
12                  {
13                       if  (attribute.Name.LocalName  ==   " xmlns " )
14                      {
15                          style.Namespaces.Add( "" , attribute.Value);
16                      }
17                       else   if  (attribute.Name.NamespaceName  ==  XNamespace.Xmlns.NamespaceName)
18                      {
19                          style.Namespaces.Add(attribute.Name.LocalName, attribute.Value);
20                      }
21                  }
22 
23                   //  Get the styles and shared resources
24                   foreach  (XElement element  in  root.Elements())
25                  {
26                       string  name  =  (element.Name.LocalName  ==   " Style " ?
27                          GetAttribute(element,  " TargetType " " Key " " Name " ) :
28                          GetAttribute(element,  " Key " " Name " );
29                       if  (style.Resources.ContainsKey(name))
30                      {
31                           throw   new  InvalidOperationException( string .Format(
32                              CultureInfo.InvariantCulture,
33                               " Resource \ " { 0 }\ "  is used multiple times in {1} (possibly as a Key, Name, or TargetType)! " ,
34                              name,
35                              path));
36                      }
37                      style.Resources.Add(name, element);
38                      style.MergeHistory[name]  =  path;
39                  }
40              }
41 
42               return  style;
43          }
44 
45           private   static   string  GetAttribute(XElement element,  params   string [] attributes)
46          {
47               foreach  ( string  name  in  attributes)
48              {
49                   string  value  =
50                      (from a  in  element.Attributes()
51                        where  a.Name.LocalName  ==  name
52                       select a.Value)
53                       .FirstOrDefault();
54                   if  (name  !=   null )
55                  {
56                       return  value;
57                  }
58              }
59               return   "" ;
60          }
61 
修改后的代码
 1  public   static  DefaultStyle Load( string  path)
 2  {
 3      DefaultStyle style  =   new  DefaultStyle();
 4      style.DefaultStylePath  =  path;
 5 
 6       string  xaml  =  File.ReadAllText(path);
 7      XElement root  =  XElement.Parse(xaml, LoadOptions.PreserveWhitespace);
 8       if  (root.Name.LocalName  ==  RootElement)
 9      {
10           //  Get the namespaces   
11           foreach  (XAttribute attribute  in  root.Attributes())
12          {
13               if  (attribute.Name.LocalName  ==   " xmlns " )
14              {
15                  style.Namespaces.Add( "" , attribute.Value);
16              }
17               else   if  (attribute.Name.NamespaceName  ==  XNamespace.Xmlns.NamespaceName)
18              {
19                  style.Namespaces.Add(attribute.Name.LocalName, attribute.Value);
20              }
21          }
22 
23           //  Get the styles and shared resources   
24           foreach  (XElement element  in  root.Elements())
25          {
26               // 此处进行了修改
27               string  name  =  (element.Name.LocalName  ==   " Style " ?
28                  GetAttribute(element,  " Key " " Name " " TargetType " ) :
29                  GetAttribute(element,  " Key " " Name " );
30               if  (style.Resources.ContainsKey(name))
31              {
32                   throw   new  InvalidOperationException( string .Format(
33                      CultureInfo.InvariantCulture,
34                       " Resource \ " { 0 }\ "  is used multiple times in {1} (possibly as a Key, Name, or TargetType)! " ,
35                      name,
36                      path));
37              }
38              style.Resources.Add(name, element);
39              style.MergeHistory[name]  =  path;
40          }
41      }
42 
43       return  style;
44  }
45 
46  private   static   string  GetAttribute(XElement element,  params   string [] attributes)
47  {
48       foreach  ( string  name  in  attributes)
49      {
50           string  value  =
51              (from a  in  element.Attributes()
52                where  a.Name.LocalName  ==  name
53               select a.Value)
54               .FirstOrDefault();
55           // 此处进行了修改
56           if  (value  !=   null )
57          {
58               return  value;
59          }
60      }
61       return   "" ;
62  }
63 

 

OK,代码添加完毕,编译后就得到了一个自定义任务的实现类,接下来就是对要进行自定任务运行的项目文件进行编辑。

       首先,在VS中右键Unload你要编辑的项目,然后右键选择编辑改项目,在<Project节点的下面加上如下的自定义任务的声明,如下:

自定义任务的声明
1  < Project  ToolsVersion ="3.5"  DefaultTargets ="Build"  xmlns ="http://schemas.microsoft.com/developer/msbuild/2003" >
2     < UsingTask
3     TaskName ="Engineering.Build.Tasks.MergeDefaultStylesTask"
4    AssemblyFile ="$(EngineeringResources)\Engineering.Build.dll"   />
5 

其中TaskName为刚才新建的Task类的全名,AssemblyFile为该类所在的程序集的物理地址,这里使用了一个预先的符号,你需要将其改成自己的实际地址。

       然后,在之前的定义下面添加一个ItemGroup,这样可以让VS识别到这个Build Action,定义如下:

Build Action
1     <!--  Add "DefaultStyle" as a Build Action in Visual Studio  -->
2     < ItemGroup  Condition ="'$(BuildingInsideVisualStudio)'=='true'" >
3       < AvailableItemName  Include ="DefaultStyle"   >
4         < Visible > false </ Visible >
5       </ AvailableItemName >
6     </ ItemGroup >
7 

注意这里跟原文不同的是添加了一个<Visible>false</Visible>属性,你可以尝试将其去掉,会发现在项目中多出了一个名为DefaultStyle的文件。

       最后,添加自定义任务的执行,这也是我卡住的地方,最后发现可能是由于项目文件是在VS中生成的原因,原文中的Targer定义之后不起作用,而是需要将其定义放到VS生成的项目文件所指定的位置,具体位置如下:

Targer
1  <!--  To modify your build process, add your task inside one of the targets below and uncomment it. 
2         Other similar extension points exist, see Microsoft.Common.targets.   -->
3     < Target  Name ="BeforeBuild" >
4     </ Target >
5     < Target  Name ="AfterBuild"  Inputs ="@(DefaultStyle)"  Outputs ="$(ProjectDir)\Themes\Generic.xaml" >
6       < MergeDefaultStylesTask  DefaultStyles ="@(DefaultStyle)"  ProjectDirectory ="$(ProjectDir)"   />
7     </ Target >
8 

按照字面的意思,我选择了在编译成功后执行我们的自定义任务,关于为什么必须在这里添加的任务才会执行,由于我对于MSBuild方面知识的匮乏,无法给大家一个解释,我猜测可能是下面这句话的原因:

<Import Project="$(MSBuildExtensionsPath32)\Microsoft\Silverlight\v3.0\Microsoft.Silverlight.CSharp.targets" />

时间有限,暂时还不想将时间放在了解MSBuild,希望有知道的朋友能够给以回复。

       好了,按照上面的流程就完成了整个任务的定义,以后你只需要在修改了某个资源文件后,点击Build,该任务就会自动帮你把所有Build Action设置为DefaultStyle的资源文件进行合并。

       PS:目前只能在有相应的资源文件被修改后Build才会进行合并操作,而在原文中还有一个任务,能够在Rebuild的时候强制合并资源文件,但是我添加后并没有起作用,如果有了解的朋友,还希望能够在回复中给与指出,不甚感激!

 

你可能感兴趣的:(silverlight)