项目模板参数化(下)

本篇主要来介绍一下怎么利用IWizard接口提供的代码向导动态进行参数的设值。

方式三:利用IWizard接口动态设值

1,首先我们先看一下IWizard这个接口,这个接口第一在Microsoft.VisualStudio.TemplateWizardInterface.dll这个程序集中,命名空间为Microsoft.VisualStudio.TemplateWizard,签名如下: 

   1: public interface IWizard
   2: {
   3:     void BeforeOpeningFile(ProjectItem projectItem);
   4:     void ProjectFinishedGenerating(Project project);
   5:     void ProjectItemFinishedGenerating(ProjectItem projectItem);
   6:     void RunFinished();
   7:     void RunStarted(object automationObject, Dictionary<string, string> replacementsDictionary, WizardRunKind runKind, object[] customParams);
   8:     bool ShouldAddProjectItem(string filePath);
   9: }

我们暂时先不深入展开这个接口,界于我们讨论的主题,这里我们只要知道两个结论,我先给出这两个结论:

1)当我们用“新建项目”对话框新建项目,按下确定时,Visual Studio会实例化这个接口的实现(Visual Studio怎么知道要实例哪个接口实现呢,下文会给出),并且执行Runstarted这个方法。

2)关于RunStarted方法,这个方法的第二个参数是一个Dictionary<string, string>,通过这个字典,我们可以添加新的Key-Value,Key就是我们要添加的参数,Value就是我们要添加的参数的值,实现IWizard接口动态设值。

2,我们来添加一个TemplateWizard类库,添加EnvDTE和Microsoft.VisualStudio.TemplateWizardInterface这两个程序集引用。我们这个类库是需要强签名的,因为最后要部署到GAC里面。

 clip_image001

添加一个DynamicCustomParameterWizard类,让它实现IWizard接口,代码如下: 

   1: public class DynamicCustomParameterWizard : IWizard
   2: {
   3:     #region Implementation of IWizard
   4:  
   5:     public void RunStarted(object automationObject, Dictionary<string, string> replaceme
   6:     {
   7:         if (replacementsDictionary != null)
   8:         {
   9:             //$CurrentTimeWithFormat$
  10:             replacementsDictionary["$CurrentTimeWithFormat$"] = DateTime.Now.ToString("y
  11:  
  12:             //$AllExistingKeyValues$
  13:             StringBuilder stringBuilder = new StringBuilder();
  14:             foreach (var item in replacementsDictionary)
  15:             {
  16:                 stringBuilder.Append(item.Key.PadRight(40));
  17:                 stringBuilder.Append(item.Value);
  18:         stringBuilder.Append("=".PadRight(10));
  19:                 stringBuilder.Append("\r\n");
  20:             }
  21:             replacementsDictionary["$AllExistingKeyValues$"] = stringBuilder.ToString();
  22:         }
  23:     }
  24:  
  25:     public bool ShouldAddProjectItem(string filePath)
  26:     {
  27:         return true;
  28:     }
  29:  
  30:     public void RunFinished()
  31:     {
  32:     }
  33:  
  34:     public void BeforeOpeningFile(ProjectItem projectItem)
  35:     {
  36:     }
  37:  
  38:     public void ProjectItemFinishedGenerating(ProjectItem projectItem)
  39:     {
  40:     }
  41:  
  42:     public void ProjectFinishedGenerating(Project project)
  43:     {
  44:     }
  45:  
  46:     #endregion
  47: }

当然,我们还要新建一个DynamicCustomParameterExperiment.txt,

CurrentTimeWithFormat                =        $CurrentTimeWithFormat$ 
AllExistingKeyValues: 
$AllExistingKeyValues$

以及,添加元数据到项目元数据文件中: 

<ProjectItem ReplaceParameters="true">DynamicCustomParameterExperiment.txt</ProjectItem>


这时候,该解决前面留下的一个问题了,怎么让Visual Studio知道WebClient这个子项目模板要依赖我们定义好的DynamicCustomParameterWizard实现,既然我们说过,模板元数据文件是纽带,所以这里有一个新的节点可以定义这种接口向导实现,直接定义在VSTemplate根节点下: 

 

<WizardExtension>
  <Assembly>Ethan.Woo.TemplateWizard, Version=1.0.0.0, Culture=neutral, PublicKeyToken=e82b5e824e88ddd5</Assembly>
  <FullClassName>Ethan.Woo.TemplateWizard.DynamicCustomParameterWizard</FullClassName>
</WizardExtension>

3,部署和使用:项目模板的ZIP包还是和之前一样做法,注意,这里接口向导所在的程序集由于要部署到GAC里,所以,不需要打到这个ZIP包里面。既然Visual Studio有这个GAC部署接口向导程序集的限制,且不是给我们的一站式部署带来了麻烦?是的,确实是个问题,但是可以解决,我们在以后的文章中再专门探讨这个问题。

部署好ZIP包和程序集以后,我们来看下新建项目后的效果:

image

Tips:如果我们在开发一个复杂的IWizard接口实现,经常需要调试新版本时,手工部署GAC是很麻烦的,这里我推荐使用Build Events机制(Post-build event command line):

"C:\Program Files\Microsoft SDKs\Windows\v7.0A\bin\NETFX 4.0 Tools\gacutil.exe" /u "Ethan.Woo.TemplateWizard, Version=1.0.0.0, Culture=neutral, PublicKeyToken=e82b5e824e88ddd5" 
"C:\Program Files\Microsoft SDKs\Windows\v7.0A\bin\NETFX 4.0 Tools\gacutil.exe" /i "$(TargetPath)"

这篇文章还没有到结束的时候,让我们分析一下这个替换的结果,从这个结果可以得出一些新的结论:

1)在RunStarted这个方法开始执行的时候,方式一和方式二指定的参数已经有值,并且被置入这个Dictionary里面,分别对应绿色和灰色。蓝色的部分很明显,是方式三动态加入的。那么红色的部分是哪里来的,我推断最大的可能是,微软MSDN中没有公布出来或者漏掉的系统参数。

2)由于RunStarted这个方法公布了这个Dictionary,并且有结论1,那么,我们完全可以覆盖掉已经存在的参数和值,这在某些特殊场合是有用的。

这篇文章,已经对我们的话题阐述到位了,但是,对于IWizard的讨论,还没有结束,下一篇,我会深入来看一下IWizard这个接口。

 

摘自:http://www.ethan-woo.com/post/2011/05/02/VisualStudio-Template-Parameterization-Second.aspx

posted @ 2011-12-15 16:18  WarrenHu  阅读(357)  评论(0编辑  收藏  举报