建立基本的專案系統,第 1 部分
在 Visual Studio 中,專案是開發人員用來組織原始碼檔案和其他資產的容器。 專案會在方案總管中顯示為方案的子系。 專案可讓您組織、建置、偵錯及部署原始程式碼,以及建立 Web 服務、資料庫和其他資源的參考。
專案定義於專案檔中,例如 .csproj 檔案用於 Visual C# 專案。 您可以建立自己的專案類型,並具有專屬的專案副檔名。 如需專案類型的詳細資訊,請參閱專案類型。
注意
如果您需要使用自訂專案類型來擴充 Visual Studio,強烈建議您利用 Visual Studio 專案系統 (VSPS),相較於從頭開始建置專案系統,這具有幾個優點:
更容易上線。 即使是基本專案系統也需要數萬行程式碼。 利用 VSPS 可讓您在準備好根據需求進行自訂前,將上線成本減少為只需幾個按鍵。
更容易維護。 利用 VSPS,您只需要維護自己的案例。 我們會處理所有專案系統基礎結構的維護工作。
如果您需要以 Visual Studio 2013 之前的 Visual Studio 版本為目標,您將無法在 Visual Studio 延伸模組中運用 VSPS。 如果是這種情況,本逐步解說是開始著手的好地方。
本逐步解說說明如何建立專案副檔名 .myproj 的專案類型。 本逐步解說會借用現有的 Visual C# 專案系統。
注意
如需延伸模組專案的詳細資訊,請參閱 VSSDK 範例。
本逐步解說教導如何完成以下任務:
建立基本專案類型。
建立基本專案範本。
向 Visual Studio 註冊專案範本。
開啟 [新增專案] 對話方塊,然後使用範本來建立專案執行個體。
為您的專案系統建立專案處理站。
為您的專案系統建立專案節點。
為專案系統新增自訂圖示。
實作基本範本參數替代。
必要條件
下載適用於專案的 Managed Package Framework 原始程式碼。 將檔案解壓縮到您要建立之方案可存取的位置。
建立基本專案類型
建立名為 SimpleProject 的 C# VSIX 專案。 ([檔案]>[新增]>[專案],然後 [Visual C#]>[擴充性]>[VSIX 專案])。 新增 Visual Studio 套件專案項目範本 (在 [方案總管]上,以滑鼠右鍵按一下專案節點,並選取 [新增]>[新增項目],然後移至 [擴充性]>[Visual Studio 套件])。 將檔案命名為 SimpleProjectPackage。
建立基本專案範本
現在,您可以修改這個基本 VSPackage 來實作新的 .myproj 專案類型。 若要建立以 .myproj 專案類型為基礎的專案,Visual Studio 必須知道要新增至新專案的檔案、資源和參考。 若要提供這項資訊,請將專案檔放在專案範本資料夾中。 當使用者使用 .myproj 專案建立專案時,會將檔案複製到新專案。
建立基本專案範本
將三個資料夾新增至專案,將一個放在另一個底下:Templates\Projects\SimpleProject。 (在 [方案總管]中,以滑鼠右鍵按一下 [SimpleProject] 專案節點,指向 [新增],然後按一下 [新增資料夾]。將資料夾命名為 Templates。在 [Templates] 資料夾中,新增名為 Projects 的資料夾。在 [Projects] 資料夾中,新增名為 SimpleProject 的資料夾。
在 Templates\Projects\SimpleProject 資料夾中,新增點陣圖影像檔案,用作為名為 SimpleProject.ico 的圖示。 當您按一下 [新增] 時,圖示編輯器隨即開啟。
讓圖示與眾不同。 本圖示會出現在逐步解說稍後的 [新增專案] 對話方塊中。
儲存圖示並關閉圖示編輯器。
在 Templates\Projects\SimpleProject 資料夾中,新增名為 Program.cs 的 Class 項目。
將現有的程式碼取代為下列幾行。
using System; using System.Collections.Generic; using System.Text; namespace $nameSpace$ { public class $className$ { static void Main(string[] args) { Console.WriteLine("Hello VSX!!!"); Console.ReadKey(); } } }
重要
這不是 Program.cs 程式碼的最終形式;取代參數會在稍後的步驟中處理。 您可能會看到編譯錯誤,但只要檔案的 BuildAction 是 Content,您應該能夠如往常建置並執行專案。
儲存檔案。
將 AssemblyInfo.cs 檔案從 [Properties] 資料夾複製到 [Projects\SimpleProject] 資料夾。
在 [Projects\SimpleProject] 資料夾中,新增名為 SimpleProject.myproj 的 XML 檔案。
注意
所有此類專案的副檔名為 .myproj。 如果您想要變更它,必須在逐步解說中任何提及它的地方進行變更。
將現有內容取代為下列幾行。
<?xml version="1.0" encoding="utf-8" ?> <Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> <PropertyGroup> <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> <SchemaVersion>2.0</SchemaVersion> <ProjectGuid></ProjectGuid> <OutputType>Exe</OutputType> <RootNamespace>MyRootNamespace</RootNamespace> <AssemblyName>MyAssemblyName</AssemblyName> <EnableUnmanagedDebugging>false</EnableUnmanagedDebugging> </PropertyGroup> <PropertyGroup Condition=" '$(Configuration)' == 'Debug' "> <DebugSymbols>true</DebugSymbols> <OutputPath>bin\Debug\</OutputPath> </PropertyGroup> <PropertyGroup Condition=" '$(Configuration)' == 'Release' "> <DebugSymbols>false</DebugSymbols> <OutputPath>bin\Release\</OutputPath> </PropertyGroup> <ItemGroup> <Reference Include="mscorlib" /> <Reference Include="System" /> <Reference Include="System.Data" /> <Reference Include="System.Xml" /> </ItemGroup> <ItemGroup> <Compile Include="AssemblyInfo.cs"> <SubType>Code</SubType> </Compile> <Compile Include="Program.cs"> <SubType>Code</SubType> </Compile> </ItemGroup> <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" /> </Project>
儲存檔案。
在 [屬性] 視窗中,將 AssemblyInfo.cs、Program.cs、SimpleProject.ico 和 SimpleProject.myproj 的 [建置動作] 設為 [內容],並將其 [包含在 VSIX 屬性] 中設定為 [True]。
此專案範本描述的是一個具有偵錯組態和發行組態的基本 Visual C# 專案。 專案包含兩個原始程式檔、AssemblyInfo.cs 和 Program.cs,以及數個組件參考。 從範本建立專案時,ProjectGuid 值會自動以新的 GUID 取代。
在 [方案總管]中,展開的 [Templates] 資料夾應該如下所示:
Templates
Projects
SimpleProject
AssemblyInfo.cs
Program.cs
SimpleProject.ico
SimpleProject.myproj
建立基本專案處理站
您必須告訴 Visual Studio 專案範本資料夾的位置。 若要這麼做,請將屬性新增至實作專案處理站的 VSPackage 類別,以便在建置 VSPackage 時將範本位置寫入系統登錄。 首先,建立依專案處理站 GUID 識別的基本專案處理站。 使用 ProvideProjectFactoryAttribute 屬性將專案處理站連接到 SimpleProjectPackage
類別。
建立基本專案處理站
為您的專案處理站建立 GUID (在 [工具] 功能表上,按一下 [建立 GUID]),或使用下列範例中的 GUID。 將 GUID 新增至包含已定義
PackageGuidString
的區段附近的SimpleProjectPackage
類別。 GUID 必須同時位於 GUID 表單和字串表單中。 產生的程式碼應該與下列範例類似。public sealed class SimpleProjectPackage : Package { ... public const string SimpleProjectPkgString = "96bf4c26-d94e-43bf-a56a-f8500b52bfad"; public const string SimpleProjectFactoryString = "471EC4BB-E47E-4229-A789-D1F5F83B52D4"; public static readonly Guid guidSimpleProjectFactory = new Guid(SimpleProjectFactoryString); }
將類別新增至名為 SimpleProjectFactory.cs 的最上層 [SimpleProject] 資料夾。
新增以下 using 指示詞:
using System.Runtime.InteropServices; using Microsoft.VisualStudio.Shell;
將 GUID 屬性新增至
SimpleProjectFactory
類別。 屬性的值是新的專案處理站 GUID。[Guid(SimpleProjectPackage.SimpleProjectFactoryString)] class SimpleProjectFactory { }
您現在可以註冊專案範本了。
註冊專案範本
在 SimpleProjectPackage.cs 中,將 ProvideProjectFactoryAttribute 屬性新增至
SimpleProjectPackage
類別,如下所示。[ProvideProjectFactory( typeof(SimpleProjectFactory), "Simple Project", "Simple Project Files (*.myproj);*.myproj", "myproj", "myproj", @"Templates\Projects\SimpleProject", LanguageVsTemplate = "SimpleProject")] [Guid(SimpleProjectPackage.PackageGuidString)] public sealed class SimpleProjectPackage : Package
重建方案並確認建置沒有發生錯誤。
重建作業會註冊專案範本。
參數
defaultProjectExtension
和possibleProjectExtensions
會設定為專案副檔名 (.myproj)。projectTemplatesDirectory
參數會設定為 [Templates] 資料夾的相對路徑。 在建置期間,此路徑會轉換成完整組建,並新增至登錄以註冊專案系統。
測試範本註冊
範本註冊會向 Visual Studio 告知專案範本資料夾的位置,讓 Visual Studio 可以在 [新增專案] 對話方塊中顯示範本名稱和圖示。
測試範本註冊
按 F5 開始對 Visual Studio 的實驗執行個體進行偵錯。
在實驗執行個體中,建立新建之專案類型的新專案。 在 [新增專案] 對話方塊中,您應該會在 [已安裝的範本] 底下看到 [SimpleProject]。
您現在有一個已註冊的專案處理站。 不過,它尚無法建立專案。 專案套件和專案處理站會共同運作,以建立和初始化專案。
新增 Managed Package Framework 程式碼
實作專案套件與專案處理站之間的連線。
匯入 Managed Package Framework 的原始碼檔案。
卸載 SimpleProject 專案 (在 [方案總管]中,選取專案節點,然後在操作功能表上按一下 [卸載專案]。),並在 XML 編輯器中開啟專案檔。
將下列區塊新增至專案檔 (在 <Import> 區塊正上方)。 在您剛才下載的 Managed Package Framework 程式碼中,將
ProjectBasePath
設定為 ProjectBase.files 檔案的位置。 您可能需要在 pathname 加入反斜線。 如果不這麼做,專案可能找不到 Managed Package Framework 原始程式碼。<PropertyGroup> <ProjectBasePath>your path here\</ProjectBasePath> <RegisterWithCodebase>true</RegisterWithCodebase> </PropertyGroup> <Import Project="$(ProjectBasePath)\ProjectBase.Files" />
重要
別忘了路徑結尾的反斜線。
重新載入專案。
加入下列組件的參考:
Microsoft.VisualStudio.Designer.Interfaces
(在 <VSSDK install>\VisualStudioIntegration\Common\Assemblies\v2.0 中)WindowsBase
Microsoft.Build.Tasks.v4.0
初始化專案處理站
在 SimpleProjectPackage.cs 檔案中,新增下列
using
指示詞。using Microsoft.VisualStudio.Project;
從
Microsoft.VisualStudio.Package.ProjectPackage
衍生SimpleProjectPackage
類別。public sealed class SimpleProjectPackage : ProjectPackage
註冊專案處理站。 在
base.Initialize
之後的SimpleProjectPackage.Initialize
方法中加入下列幾行:base.Initialize(); this.RegisterProjectFactory(new SimpleProjectFactory(this));
實作抽象屬性
ProductUserContext
:public override string ProductUserContext { get { return ""; } }
在 SimpleProjectFactory.cs 中,於現有的
using
指示詞後面新增下列using
指示詞。using Microsoft.VisualStudio.Project;
從
ProjectFactory
衍生SimpleProjectFactory
類別。class SimpleProjectFactory : ProjectFactory
將下列虛擬方法新增至
SimpleProjectFactory
類別。 您會在稍後的章節中實作這個方法。protected override ProjectNode CreateProject() { return null; }
將以下欄位和建構函式新增至
SimpleProjectFactory
類別。 此SimpleProjectPackage
參考會快取在私人欄位中,以便用於設定服務提供者網站。private SimpleProjectPackage package; public SimpleProjectFactory(SimpleProjectPackage package) : base(package) { this.package = package; }
重建方案並確認建置沒有發生錯誤。
測試專案處理站實作
測試是否會呼叫專案處理站實作的建構函式。
測試專案處理站實作
在 SimpleProjectFactory.cs 檔案中,於
SimpleProjectFactory
建構函式的下列這一行上設定中斷點。this.package = package;
按 F5 啟動 Visual Studio 的實驗執行個體。
在實驗執行個體中,開始建立新的專案。 在 [新增專案] 對話方塊中,選取 [SimpleProject] 專案類型,然後按一下 [確定]。 執行會在中斷點停止。
清除中斷點並停止偵錯。 因為我們尚未建立專案節點,因此專案建立程式碼仍然會擲回例外狀況。
擴充 ProjectNode 類別
現在您可以實作 SimpleProjectNode
類別,這是衍生自 ProjectNode
類別。 ProjectNode
基底類別會處理專案建立的下列工作:
將專案範本檔案 SimpleProject.myproj 複製到新的專案資料夾。 複本會根據 [新增專案] 對話方塊中輸入的名稱重新命名。
ProjectGuid
屬性值會以新的 GUID 取代。周遊專案範本檔案 SimpleProject.myproj 的 MSBuild 元素,並尋找
Compile
元素。 針對每個Compile
目標檔案,將檔案複製到新的專案資料夾。衍生的
SimpleProjectNode
類別會處理下列工作:在 [方案總管]中啟用要建立或選取之專案和檔案節點的圖示。
允許指定其他專案範本參數替代。
擴充 ProjectNode 類別
新增名為
SimpleProjectNode.cs
的類別。將現有的程式碼取代為下列程式碼。
using System; using System.Collections.Generic; using Microsoft.VisualStudio.Project; namespace SimpleProject { public class SimpleProjectNode : ProjectNode { private SimpleProjectPackage package; public SimpleProjectNode(SimpleProjectPackage package) { this.package = package; } public override Guid ProjectGuid { get { return SimpleProjectPackage.guidSimpleProjectFactory; } } public override string ProjectType { get { return "SimpleProjectType"; } } public override void AddFileFromTemplate( string source, string target) { this.FileTemplateProcessor.UntokenFile(source, target); this.FileTemplateProcessor.Reset(); } } }
這個
SimpleProjectNode
類別實作具有這些覆寫的方法:
ProjectGuid
,會傳回專案處理站 GUID。ProjectType
,會傳回專案型別的當地語系化名稱。AddFileFromTemplate
,會將選取的檔案從範本資料夾複製到目的地專案。 這個方法會在稍後的章節中進一步實作。SimpleProjectNode
建構函式就像SimpleProjectFactory
建構函式一樣,會在私用欄位中快取SimpleProjectPackage
參考以供稍後使用。若要將
SimpleProjectFactory
類別連接到SimpleProjectNode
類別,您必須在SimpleProjectFactory.CreateProject
方法中具現化新的SimpleProjectNode
,並將其快取在私用欄位中,以供稍後使用。
連接專案處理站類別和節點類別
在 SimpleProjectFactory.cs 檔案中,新增下列
using
指示詞。using IOleServiceProvider = Microsoft.VisualStudio.OLE.Interop.IServiceProvider;
使用下列程式碼取代
SimpleProjectFactory.CreateProject
方法。protected override ProjectNode CreateProject() { SimpleProjectNode project = new SimpleProjectNode(this.package); project.SetSite((IOleServiceProvider) ((IServiceProvider)this.package).GetService( typeof(IOleServiceProvider))); return project; }
重建方案並確認建置沒有發生錯誤。
測試 ProjectNode 類別
測試您的專案處理站,查看它是否建立專案階層。
測試 ProjectNode 類別
按 F5 開始偵錯作業。 在實驗執行個體中,建立新的 SimpleProject。
Visual Studio 應該會呼叫您的專案處理站來建立專案。
關閉 Visual Studio 的實驗執行個體。
新增自訂專案節點圖示
上一節中的專案節點圖示是預設圖示。 您可以將它變更為自訂圖示。
新增自訂專案節點圖示
在 [Resources] 資料夾中,新增名為 SimpleProjectNode.bmp 的點陣圖檔案。
在 [屬性] 視窗中,將點陣圖縮減為 16 x 16 像素。 讓點陣圖與眾不同。
在 [屬性] 視窗中,將點陣圖的 [建置動作] 變更為 [內嵌資源]。
在 SimpleProjectNode.cs 中,新增下列
using
指示詞:using System.Drawing; using System.Windows.Forms;
將以下靜態欄位和建構函式新增至
SimpleProjectNode
類別。private static ImageList imageList; static SimpleProjectNode() { imageList = Utilities.GetImageList( typeof(SimpleProjectNode).Assembly.GetManifestResourceStream( "SimpleProject.Resources.SimpleProjectNode.bmp")); }
將下列屬性加入到
SimpleProjectNode
類別的開頭。internal static int imageIndex; public override int ImageIndex { get { return imageIndex; } }
將執行個體建構函式取代為下列程式碼。
public SimpleProjectNode(SimpleProjectPackage package) { this.package = package; imageIndex = this.ImageHandler.ImageList.Images.Count; foreach (Image img in imageList.Images) { this.ImageHandler.AddImage(img); } }
在靜態建構期間,
SimpleProjectNode
會從組件資訊清單資源擷取專案節點點陣圖,並快取在私人欄位中以供稍後使用。 請注意 GetManifestResourceStream 影像路徑的語法。 若要查看內嵌在組件中的資訊清單資源名稱,請使用 GetManifestResourceNames 方法。 當此方法套用至SimpleProject
組件時,結果應該如下所示:
SimpleProject.Resources.resources
VisualStudio.Project.resources
SimpleProject.VSPackage.resources
Resources.imagelis.bmp
Microsoft.VisualStudio.Project.DontShowAgainDialog.resources
Microsoft.VisualStudio.Project.SecurityWarningDialog.resources
SimpleProject.Resources.SimpleProjectNode.bmp
在執行個體建構期間,
ProjectNode
基底類別會載入 Resources.imagelis.bmp,其中內嵌了來自 Resources\imagelis.bmp 的 16 x 16 點陣圖。 這個點陣圖清單會做為ImageHandler.ImageList
供SimpleProjectNode
使用。SimpleProjectNode
會將專案節點點陣圖附加至清單。 影像清單中的專案節點點陣圖位移會快取,以供稍後用作為公用ImageIndex
屬性的值。 Visual Studio 會使用這個屬性來判斷要顯示為專案節點圖示的點陣圖。
測試自訂專案節點圖示
測試您的專案處理站,查看它是否建立具有自訂專案節點圖示的專案階層。
測試自訂專案節點圖示
開始偵錯,並在實驗執行個體中建立新的 SimpleProject。
在新建的專案中,請注意 SimpleProjectNode.bmp 用作為專案節點圖示。
在程式碼編輯器中開啟 Program.cs。 您應該會看到類似於以下程式碼的原始程式碼。
using System; using System.Collections.Generic; using System.Text; namespace $nameSpace$ { public class $className$ { static void Main(string[] args) { Console.WriteLine("Hello VSX!!!"); Console.ReadKey(); } } }
請注意,範本參數 $nameSpace$ 和 $className$ 沒有新的值。 您將在下一節中學習如何實作範本參數替代。
替代範本參數
在先前的章節中,您使用了 ProvideProjectFactory
屬性向 Visual Studio 註冊專案範本。 以這種方式註冊範本資料夾的路徑,可讓您藉由覆寫和展開 ProjectNode.AddFileFromTemplate
類別來啟用基本範本參數替代。 如需詳細資訊,請參閱產生新專案:深入探討,第二部分。
現在,將取代程式碼新增至 AddFileFromTemplate
類別。
替代範本參數
在 SimpleProjectNode.cs 檔案中,新增下列
using
指示詞。using System.IO;
使用下列程式碼取代
AddFileFromTemplate
方法。public override void AddFileFromTemplate( string source, string target) { string nameSpace = this.FileTemplateProcessor.GetFileNamespace(target, this); string className = Path.GetFileNameWithoutExtension(target); this.FileTemplateProcessor.AddReplace("$nameSpace$", nameSpace); this.FileTemplateProcessor.AddReplace("$className$", className); this.FileTemplateProcessor.UntokenFile(source, target); this.FileTemplateProcessor.Reset(); }
在方法中設定中斷點,就在
className
指派陳述式之後。指派陳述式會決定命名空間和新類別名稱的合理值。 這兩個
ProjectNode.FileTemplateProcessor.AddReplace
方法呼叫會使用這些新值來取代相對應的範本參數值。
測試範本參數替代
現在您可以測試範本參數替代了。
測試範本參數替代
開始偵錯,並在實驗執行個體中建立新的 SimpleProject。
在
AddFileFromTemplate
方法的中斷點執行停止。檢查
nameSpace
和className
參數的值。\Templates\Projects\SimpleProject\SimpleProject.myproj 專案範本檔中 <RootNamespace> 元素的值會提供給
nameSpace
。 此處的值為MyRootNamespace
。類別來源檔名的值會提供給
className
,不含副檔名。 在本例中,要複製到目的地資料夾的第一個檔案是 AssemblyInfo.cs,因此 className 的值是AssemblyInfo
。
移除中斷點,並按 F5 以繼續執行。
Visual Studio 應該會完成建立專案。
在程式碼編輯器中開啟 Program.cs。 您應該會看到類似於以下程式碼的原始程式碼。
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace MyRootNamespace { public class Program { static void Main(string[] args) { Console.WriteLine("Hello VSX!!!"); Console.ReadKey(); } } }
請注意,命名空間現在是
MyRootNamespace
,而類別名稱現在是Program
。開始對專案進行偵錯。 新專案應該在貯控台視窗中編譯、執行及顯示「Hello VSX!!!」。
恭喜! 您已實作基本的受控專案系統。