Visual Studio项目模板与向导开发
在【Xamarin+Prism开发详解系列】里面经常使用到【Prism unity app】的模板创建Prism.Forms项目:
备注:由于Unity社区已经不怎么活跃,下一个版本将会有Autofac,DryIOC,Ninject的项目模板。
自动弹出选择框:
对于我这类还没有动手写过模板的人来说,确实挺新奇的。于是就决定自己也写个类似的试试,目的就是通过向导创建跨平台Plugin项目,类似Plugin for xamarin,不过是针对Prism,对应平台可以自由选择创建。试了之后才发现也有不少注意的地方,特写下此文做备忘。
项目地址:https://github.com/NewBLife/Prism.Forms.Plugin
插件下载地址:TemplatesForPrism.vsix
1、安装插件开发用的Extensibility模板与工具
2、新建VSIX Project插件项目
source.extension.vsixmanifest 这个文件相当重要,里面可以指定安装目标,模板,向导等。
最后我实现的例子:
安装目标:VS2013以上(2017估计不行)
资产:Project模板,Item模板,Wizard向导
3、从【C# Item Template】与【C# Project Template】模板创建项目。
4、从【类库】模板创建Wizard项目。(Wizard向导只能是类库)
以上步骤之后的项目结构:
介绍:
- Prism.Forms.Plugin.Nuspec:Plugin打包文件模板
- Prism.Forms.Plugin:Plugin项目模板
- Prism.Forms.Plugin.Wizard:Plugin创建向导
- TemplatesForPrism:VSIX插件项目
5、添加引用
- Prism.Forms.Plugin.Nuspec:Microsoft.VisaulStudio.CoreUtility
- Prism.Forms.Plugin:Microsoft.VisaulStudio.CoreUtility
- Prism.Forms.Plugin.Wizard:Microsoft.VisaulStudio.TemplateWizardinterface,envdte
- TemplatesForPrism:Prism.Forms.Plugin.Nuspec,Prism.Forms.Plugin,Prism.Forms.Plugin.Wizard
6、添加生成向导
6.1、NewProjectWizard项目选择向导创建新建一个WinForm选择框,返回选择的结果。
继承IWiazrd向导接口实现:
using EnvDTE;
using Microsoft.VisualStudio.TemplateWizard;
using System;
using System.Collections.Generic;
using System.IO; namespace Prism.Forms.Plugin.Wizard
{
public class NewProjectWizard : IWizard
{
private DTE _dte = null; private string _solutionDir = null; private string _templateDir = null; private string _projectName = null; PluginNewProjectDialogResult _dialogResult; public void BeforeOpeningFile(ProjectItem projectItem)
{
} public void ProjectFinishedGenerating(Project project)
{
if
(_dialogResult.CreateAndroid) CreateProject(Target.Droid.ToString()); if (_dialogResult.CreateiOS) CreateProject(Target.iOS.ToString()); if
(_dialogResult.CreateUwp)
CreateProject(Target.UWP.ToString()); }
void CreateProject(string platform) { string name = $"{_projectName}.{platform}"; string projectPath = System.IO.Path.Combine(_solutionDir, Path.Combine(_projectName, name)); string templateName = $"Prism.Forms.Plugin.{platform}"; string templatePath = System.IO.Path.Combine(System.IO.Path.GetDirectoryName(_templateDir), $"{templateName}.zip\\{templateName}.vstemplate"
); _dte.Solution.AddFromTemplate(templatePath, projectPath, name); } public void ProjectItemFinishedGenerating(ProjectItem projectItem)
{
} public void RunFinished()
{
} public void RunStarted(object automationObject, Dictionary<string, string> replacementsDictionary, WizardRunKind runKind, object[] customParams)
{
try
{
_dte = automationObject as DTE; _projectName = replacementsDictionary["$safeprojectname$"]; _solutionDir = System.IO.Path.GetDirectoryName(replacementsDictionary["$destinationdirectory$"]); _templateDir = System.IO.Path.GetDirectoryName(customParams[] as string); PluginNewProjectDialog dialog
= new PluginNewProjectDialog(); dialog.ShowDialog(); _dialogResult =
dialog.Result; if (_dialogResult.Cancelled) throw new WizardBackoutException(); }
catch (Exception)
{
if (Directory.Exists(_solutionDir)) Directory.Delete(_solutionDir, true);
throw;
}
} public bool ShouldAddProjectItem(string filePath)
{
return true;
}
}
}
模板选择后执行RunStarted==》弹出Winform选择框==》执行ProjectFinishedGenerating创建子项目
6.2、项目名称safeprojectgroupname向导创建
在NewProjectWizard向导的CreateProject方法里面我们设置了每个子项目的名称为"{_projectName}.{platform}",所以到达子项目的时候$safeprojectname$里面已经带了iOS,Droid,UWP等名称,所以有必要进行处理。
using EnvDTE;
using Microsoft.VisualStudio.TemplateWizard;
using System.Collections.Generic;
using System.Threading; namespace Prism.Forms.Plugin.Wizard
{
public class SafeProjectGroupName : IWizard
{
public const string ParameterName = "$safeprojectgroupname$"; static ThreadLocal<string> projectGroupName = new ThreadLocal<string>();
bool isRootWizard; public void BeforeOpeningFile(ProjectItem projectItem)
{
} public void ProjectFinishedGenerating(Project project)
{
} public void ProjectItemFinishedGenerating(ProjectItem projectItem)
{
} public void RunFinished()
{
// If we were the ones to set the value, we must clear it.
if (isRootWizard)
projectGroupName.Value = null;
} public void RunStarted(object automationObject, Dictionary<string, string> replacementsDictionary, WizardRunKind runKind, object[] customParams)
{
if (projectGroupName.Value == null)
{
var name = replacementsDictionary["$safeprojectname$"];
if (name.EndsWith(Target.Abstractions.ToString()))
{
projectGroupName.Value = name.Replace($".{Target.Abstractions.ToString()}", string.Empty);
}
else if (name.EndsWith(Target.Droid.ToString()))
{
projectGroupName.Value = name.Replace($".{Target.Droid.ToString()}", string.Empty);
}
else if (name.EndsWith(Target.iOS.ToString()))
{
projectGroupName.Value = name.Replace($".{Target.iOS.ToString()}", string.Empty);
}
else if (name.EndsWith(Target.UWP.ToString()))
{
projectGroupName.Value = name.Replace($".{Target.UWP.ToString()}", string.Empty);
}
// If there wasn't a value already, it means we're the root wizard itself.
isRootWizard = true;
} replacementsDictionary[ParameterName] = projectGroupName.Value;
} public bool ShouldAddProjectItem(string filePath)
{
return true;
}
}
}
Debug测试方法:
- 给类库添加署名,否则无法注册
- 管理员权限启动VS2015 开发人员命令提示工具
- 导航到wizard生成目录
- 执行gacutil -if Prism.Forms.Plugin.Wizard.dll 命令注册类库
- 执行gacutil –l 列出类库的Token信息(Prism.Forms.Plugin.Wizard, Version=1.0.0.0, Culture=neutral, PublicKeyToken=b2335488e79a16da, processorArchitecture=MSIL)
- 模板文件的WizarExtension节点添加以上Token信息与入口类名称
- 安装模板,设置断点
- 启动另一个Visual Studio程序
- 调试-》附加到进程-》附加新启动的Visual Studio进程
- 新Visual Studio窗口选择建立的模板,将进入断点
7、添加模板文件并设置
Prism.Forms.Plugin.Nuspec模板设置
<?xml version="1.0" encoding="utf-8"?>
<VSTemplate Version="3.0.0" Type="Item" xmlns="http://schemas.microsoft.com/developer/vstemplate/2005" xmlns:sdk="http://schemas.microsoft.com/developer/vstemplate-sdkextension/2010">
<TemplateData>
<Name>Plugin nuspec for Prism.Forms</Name>
<Description>Create a nuspec file for Prism.Forms.Plugin solution</Description>
<Icon>Prism.Forms.Plugin.Nuspec.ico</Icon>
<TemplateID>325a0391-d11c---b70405881e87</TemplateID>
<ProjectType>General</ProjectType>
<RequiredFrameworkVersion>2.0</RequiredFrameworkVersion>
<NumberOfParentCategoriesToRollUp></NumberOfParentCategoriesToRollUp>
<DefaultName>PrismFormsPlugin.nuspec</DefaultName>
</TemplateData>
<TemplateContent>
<ProjectItem TargetFileName="$fileinputname$.nuspec" ReplaceParameters="true">Prism.Forms.Plugin.nuspec</ProjectItem>
</TemplateContent>
</VSTemplate>
注意点:
- Item模板的ProjectType默认为CSharp,有时候没法找到,最好设置为General。
- 模板参照文件的生成操作都设置为无。
- 记得设置分类Category,这样好找。
效果如下:(在添加新项里面)
Prism.Forms.Plugin模板设置
每个文件夹下面为相应的模板文件
- Prism.Forms.Plugin.Abstractions:接口定义
- Prism.Forms.Plugin.Droid:Android平台特性的接口实现
- Prism.Forms.Plugin.iOS:iOS平台特性的接口实现
- Prism.Forms.Plugin.UWP:UWP平台特性的接口实现
最外面的入口模板文件Prism.Forms.Plugin.vstemplate设置:
<?xml version="1.0" encoding="utf-8"?>
<VSTemplate Version="3.0.0"
Type="ProjectGroup"
xmlns="http://schemas.microsoft.com/developer/vstemplate/2005" xmlns:sdk="http://schemas.microsoft.com/developer/vstemplate-sdkextension/2010">
<TemplateData>
<Name>Plugin for Prism.Forms</Name>
<Description>Creates all files necessary to create a plugin for Prism.Forms</Description>
<Icon>Prism.Forms.Plugin.ico</Icon>
<ProjectType>CSharp</ProjectType>
<RequiredFrameworkVersion>2.0</RequiredFrameworkVersion>
<SortOrder></SortOrder>
<TemplateID>16bac5e1-199d-4e08-9ed3-2ef287221be1</TemplateID>
<DefaultName>PrismFormsPlugin</DefaultName>
<ProvideDefaultName>true</ProvideDefaultName>
<PromptForSaveOnCreation>true</PromptForSaveOnCreation>
<NumberOfParentCategoriesToRollUp></NumberOfParentCategoriesToRollUp>
</TemplateData>
<TemplateContent>
<ProjectCollection> <ProjectTemplateLink ProjectName="$safeprojectname$.Abstractions">
Prism.Forms.Plugin.Abstractions\Prism.Forms.Plugin.Abstractions.vstemplate
</ProjectTemplateLink> </ProjectCollection>
</TemplateContent>
<WizardExtension> <Assembly>Prism.Forms.Plugin.Wizard, Version=1.0.0.0, Culture=neutral, PublicKeyToken=b2335488e79a16da</Assembly> <FullClassName>Prism.Forms.Plugin.Wizard.NewProjectWizard</FullClassName> </WizardExtension>
</VSTemplate>
注意点:
- 入口模板文件的Type必须为ProjectGroup,否则只创建一个工程项目
- 模板内容必须使用ProjectTemplateLink添加每个子项目的模板文件设置
- 由于使用向导可选择方式创建子项目,所有这里只添加了接口的模板文件
- WizarExtension节点为向导程序设置,调用Prism.Forms.Plugin.Wizard.NewProjectWizard
子项目模板Prism.Forms.Plugin.Abstractions.vstemplate设置:
<VSTemplate Version="3.0.0" xmlns="http://schemas.microsoft.com/developer/vstemplate/2005"
Type="Project">
<TemplateData>
<Name>Prism.Forms.Plugin.Abstractions</Name>
<Description>Implementation Interface for Prism.Forms.Plugin </Description>
<ProjectType>
CSharp
</ProjectType>
<ProjectSubType>
</ProjectSubType>
<SortOrder></SortOrder>
<CreateNewFolder>true</CreateNewFolder>
<DefaultName>Prism.Forms.Plugin.Abstractions</DefaultName>
<ProvideDefaultName>true</ProvideDefaultName>
<LocationField>Enabled</LocationField>
<EnableLocationBrowseButton>true</EnableLocationBrowseButton>
<Icon>__TemplateIcon.ico</Icon>
<PromptForSaveOnCreation>true</PromptForSaveOnCreation>
</TemplateData>
<TemplateContent>
<Project TargetFileName="$safeprojectname$.Abstractions.csproj" File="Prism.Forms.Plugin.Abstractions.csproj" ReplaceParameters="true">
<ProjectItem ReplaceParameters="true" TargetFileName="I$safeprojectgroupname$.cs">IPrismFormsPlugin.cs</ProjectItem>
<Folder Name="Properties" TargetFolderName="Properties">
<ProjectItem ReplaceParameters="true" TargetFileName="AssemblyInfo.cs">AssemblyInfo.cs</ProjectItem>
</Folder>
</Project>
</TemplateContent>
<WizardExtension> <Assembly>Prism.Forms.Plugin.Wizard, Version=1.0.0.0, Culture=neutral, PublicKeyToken=b2335488e79a16da</Assembly> <FullClassName>Prism.Forms.Plugin.Wizard.SafeProjectGroupName</FullClassName> </WizardExtension>
</VSTemplate>
注意点:
- Type为Project。
- safeprojectgroupname是Prism.Forms.Plugin.Wizard.SafeProjectGroupName向导提供的参数,不是VS内部参数。值为用户选择模板时输入的工程名称。
- 模板参照文件(IPrismFormsPlugin.cs,AssemblyInfo.cs等)的生成操作设置为无,否则编译出错。
IPrismFormsPlugin.cs设置:使用safeprojectgroupname
using System; namespace $safeprojectgroupname$
{
public interface I$safeprojectgroupname$
{
}
}
Prism.Forms.Plugin.Abstractions.csproj设置:使用safeprojectgroupname
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<MinimumVisualStudioVersion>10.0</MinimumVisualStudioVersion>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{$guid1$}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>$safeprojectgroupname$</RootNamespace> <AssemblyName>$safeprojectname$</AssemblyName>
<DefaultLanguage>en-US</DefaultLanguage>
<FileAlignment></FileAlignment>
<ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
<TargetFrameworkProfile>Profile7</TargetFrameworkProfile>
<TargetFrameworkVersion>v4.</TargetFrameworkVersion>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel></WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel></WarningLevel>
<DocumentationFile>bin\Release\$safeprojectname$.XML</DocumentationFile>
</PropertyGroup>
<ItemGroup>
<!-- A reference to the entire .NET Framework is automatically included -->
</ItemGroup>
<ItemGroup>
<Compile Include="I$safeprojectgroupname$.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\Portable\$(TargetFrameworkVersion)\Microsoft.Portable.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>
总体文件结构如下:
备注:
IPrismFormsPlugin.cs,AssemblyInfo.cs,Prism.Forms.Plugin.Abstractions.csproj等都是通过VS自动生成的,不是手工创建的。具体方法就是事先建立后想要的项目结构与文件,然后使用VS的导出模板功能就可以自动生成了。添加进模板项目的时候一定记得将生成操作设置为无。
8、插件source.extension.vsixmanifest文件设置
添加安装目标,资产。
9、生成发布
使用效果如下:
这回再也不用每次都添加好几次工程了,一次搞定。懒人就是这样想办法偷懒。
Visual Studio项目模板与向导开发的更多相关文章
- Visual Studio 项目模板制作(一)
我们编写项目的时候,很多时候都是在写重复代码,比如一个比较完整的框架,然后下面有很多代码都是重复的Copy,其实我们可以利用Visual Studio的模板替我们干这些活,我们只要关注项目具体的业务就 ...
- Visual Studio 项目模板制作(三)
前面,我们已经制作好了模板,然后放到相应的Template目录就可以在Visual Studio中使用 本篇,我们采用安装VSIX扩展的方式来安装模板,这种方式需要安装Visual Studio SD ...
- Visual Studio 项目模板制作(二)
上一篇,我们制作了项目模板,本篇我制作项模板 首先,从我们需要导出模板的项目中,文件->导出模板,弹出 导出模板向导 对话框 选择项模板,点击下一步 选择要导出的项,点击下一步 选择要Refer ...
- Visual Studio 项目模板制作(四)
上一篇,介绍了VSIX安装模板的方法,那么,你是不是要问,为何有些项目模板却可以有向导,那是怎么做到的 今天这篇文章就是介绍如何为自己的模板添加向导,向导可以引导你完成项目中各种参数的设置,比如项目创 ...
- 创建Visual studio项目模板 vstemplate关键点纪要
from:http://www.cnblogs.com/stickman/p/3454719.html 经过多次的实验,终于完美生成一个.VSIX的项目模板安装包,其中遇到不少问题与挫折,久经goog ...
- 在Visual Studio 2012中使用VMSDK开发领域特定语言(一)
前言 本专题主要介绍在Visual Studio 2012中使用Visualization & Modeling SDK进行领域特定语言(DSL)的开发,包括两个部分的内容.在第一部分中,将对 ...
- 在Visual Studio 2012中使用VMSDK开发领域特定语言1
在Visual Studio 2012中使用VMSDK开发领域特定语言(一) 前言 本专题主要介绍在Visual Studio 2012中使用Visualization & Modelin ...
- 在Visual Studio 2012中使用VMSDK开发领域特定语言(二)
本文为<在Visual Studio 2012中使用VMSDK开发领域特定语言>专题文章的第二部分,在这部分内容中,将以实际应用为例,介绍开发DSL的主要步骤,包括设计.定制.调试.发布以 ...
- 如何利用 Visual Studio 自带工具提高开发效率
Visual Stuido 是一款强大的Windows 平台集成开发工具,你是否好好地利用了它呢? 显示行号 有些时候(比如错误定位)的时候,显示行号将有利于我们进行快速定位. 如何显示 1. 工具 ...
随机推荐
- java中堆和堆栈的区别
java中堆和堆栈的区别(一) 1.栈(stack)与堆(heap)都是Java用来在Ram中存放数据的地方.与C++不同,Java自动管理栈和堆,程序员不能直接地设置栈或堆. 2. 栈的优势是,存取 ...
- eazasyui树形菜单
//此处是easyui的json格式 var tree = { id:'', text:'', state:'', checked:'', attributes:'', children:'' } / ...
- C# MODBUS协议 上位机(转)
源:C# MODBUS协议 上位机 C#写了一款上位机监控软件,基于MODBUS_RTU协议. 软件的基本结构: 采用定时器(Timer控件)为时间片. 串口采用serialPort1_DataRec ...
- HTML表格边框的设置小技巧-表格
对于很多初学HTML的人来说,表格<table>是最常用的标签了,但对于表格边框的控制,很多初学者却不甚其解. 一般我们用表格的时候总会给它个border属性,比如:<table b ...
- Linux下mysql数据库的命令
连接数据库命令:mysql -u 用户名 -p 密码 要求你输入要连接数据库的用户名和密码.用户名默认root密码不方便输入时,可以只输入:mysql -u 用户名 -p 然后回车,此时提示你输入密码 ...
- mvn
http://blog.csdn.net/z69183787/article/category/2265961
- 23、手把手教你Extjs5(二十三)模块Form的自定义的设计[2]
在本节中将要加入各种类型的字段,在加入字段的时候由于可以一行加入多个字段,因此层次结构又多了一层fieldcontainer.form里面的主要层次结构如下: form -- fieldSet -- ...
- js Date 日期格式化(转)
var myDate = new Date();myDate.getYear(); //获取当前年份(2位)myDate.getFullYear(); //获取完整的年份(4位,1 ...
- 关于Java在Linux or Android平台调用.so库
Linux平台Java调用so库-JNI使用例子 android NDK开发及调用标准linux动态库.so文件 在Android项目中调用已有.so库 Android 调用.so文件 jni And ...
- 如何在我自己的web 项目的jsp页面中添加链接,直接让别人通过内网在我的电脑上下载文件
今天接到一个任务,将昨天年会的视频,音频,图片等放在公司自己的服务器上,使连接同一个路由器的(即同一个内网)的同事可以通过内网下载视频(通过内网下载,可以提高下载速度). 备注:本次用的是tomcat ...