共用方式為


逐步解說:建立 SharePoint 專案擴充功能

本逐步解說將說明如何建立 SharePoint 專案的擴充功能。 您可以使用專案擴充功能回應專案層級事件,例如加入、刪除專案或變更專案名稱時。 您還可以加入自訂屬性或在屬性值變更時回應。 與專案項目擴充功能不同,專案擴充功能無法與特定 SharePoint 專案類型產生關聯。 當您建立專案擴充功能時,擴充功能會在任何類型的 SharePoint 專案於 Visual Studio 中開啟時載入。

在這個逐步解說中,您將建立可加入至在 Visual Studio 中所建立任何 SharePoint 專案的自訂布林屬性。 當設定為 True 時,新屬性會將 [影像] 資源資料夾加入或對應至專案。 當設定為 False 時,會移除 [影像] 資料夾 (若存在的話)。 如需詳細資訊,請參閱 HOW TO:新增與移除對應的資料夾

本逐步解說將示範下列工作:

  • 建立 SharePoint 專案的 Visual Studio 擴充功能可執行下列內容:

    • 將自訂專案屬性加入至 [屬性] 視窗。 該屬性套用至任何 SharePoint 專案。

    • 使用 SharePoint 專案物件模型將對應的資料夾加入至專案。

    • 使用 Visual Studio Automation 物件模型 (Automation Object Model,DTE),將對應的資料夾從專案刪除。

  • 建置 Visual Studio 擴充功能 (VSIX) 套件以部署專案屬性的擴充功能組件。

  • 偵錯和測試專案屬性。

必要條件

開發電腦上需要下列元件才能完成此逐步解說:

建立專案

若要完成這個逐步解說,您必須建立兩個專案:

  • VSIX 專案,用於建立 VSIX 套件以部署專案擴充功能。

  • 類別庫專案,可實作專案擴充功能。

從建立這些專案開始進行此逐步解說。

若要建立 VSIX 專案

  1. 啟動 Visual Studio。

  2. 在 [檔案] 功能表上,指向 [新增],然後按一下 [專案]。

  3. 在 [新增專案] 對話方塊中,展開 [Visual C#] 或 [Visual Basic] 節點,然後按一下 [擴充性] 節點。

    注意事項注意事項

    [擴充性] 節點只有在安裝 Visual Studio 2010 SDK 時才可使用。 如需詳細資訊,請參閱本主題稍早討論的<必要條件>一節。

  4. 在對話方塊上方的下拉式方塊中,選取 [.NET Framework 4]。 SharePoint 工具擴充功能需要這版的 .NET Framework 功能。

  5. 按一下 [VSIX 專案] 範本。

  6. 在 [名稱] 方塊中,輸入 ProjectExtensionPackage。

  7. 按一下 [確定]。

    Visual Studio 會將 [ProjectExtensionPackage] 專案加入至 [方案總管]。

若要建立擴充功能專案

  1. 在 [方案總管] 中,以滑鼠右鍵按一下方案節點,按一下 [加入],再按一下 [新增專案]。

    注意事項注意事項

    在 Visual Basic 專案中,方案節點只有在已選取選項對話方塊、專案和方案、一般中的 [永遠顯示方案] 核取方塊時,才會出現在 [方案總管] 中。

  2. 在 [新專案] 對話方塊中展開 [Visual C#] 或 [Visual Basic] 節點,然後按一下 [Windows]。

  3. 在對話方塊上方的下拉式方塊中,選取 [.NET Framework 4]。

  4. 選取 [類別庫] 專案範本。

  5. 在 [名稱] 方塊中,輸入 ProjectExtension。

  6. 按一下 [確定]。

    Visual Studio 會將 [ProjectExtension] 專案加入至方案,然後開啟預設的 Class1 程式碼檔。

  7. 從專案刪除 Class1 程式碼檔。

設定專案

在您撰寫程式碼建立專案擴充功能之前,請先將程式碼檔案和組件參考加入至擴充功能專案。

若要設定專案

  1. 將名為 CustomProperty 的新程式碼檔加入至 ProjectExtension 專案。

  2. 在 [專案] 功能表上,按一下 [加入參考]。

  3. 在 [.NET] 索引標籤上,按住 CTRL,然後按一下下列組件,再按一下 [確定]:

    • Microsoft.VisualStudio.SharePoint

    • System.ComponentModel.Composition

    • System.Windows.Forms

    • EnvDTE

  4. 在 [方案總管] 中,按一下 ProjectExtension 專案的 [參考] 資料夾底下的 [EnvDTE]。

  5. 在 [屬性] 視窗中,將 [內嵌 Interop 型別] 屬性變更為 [False]。

定義新的 SharePoint 專案屬性

建立定義專案擴充功能和新專案屬性行為的類別。 為了定義新專案擴充功能,類別會實作 ISharePointProjectExtension 介面。 在您要定義 SharePoint 專案的擴充功能時實作此介面。 另外,請將 ExportAttribute 加入至類別。 此屬性可讓 Visual Studio 探索並載入 ISharePointProjectExtension 實作。 將 ISharePointProjectExtension 型別傳遞至屬性的建構函式。

若要定義新的 SharePoint 專案屬性

  1. 如果 CustomProperty 程式碼檔案尚未開啟,請按兩下以編輯這個檔案。

  2. 將下列程式碼貼到檔案。

    Imports System
    Imports System.Linq
    Imports System.ComponentModel
    Imports System.ComponentModel.Composition
    Imports System.Windows.Forms
    Imports Microsoft.VisualStudio.SharePoint
    Imports EnvDTE
    
    Namespace Contoso.SharePointProjectExtensions.MapImagesFolder
    
        ' Export attribute: Enables Visual Studio to discover and load this extension.
        ' MapImagesFolderProjectExtension class: Adds a new Map Images Folder property to any SharePoint project.
        <Export(GetType(ISharePointProjectExtension))> _
        Public Class MapImagesFolderProjectExtension
            Implements ISharePointProjectExtension
    
            Public Sub Initialize(ByVal projectService As ISharePointProjectService) Implements ISharePointProjectExtension.Initialize
                AddHandler projectService.ProjectPropertiesRequested, AddressOf Me.projectService_ProjectPropertiesRequested
            End Sub
    
            Private Sub projectService_ProjectPropertiesRequested(ByVal sender As Object, ByVal e As SharePointProjectPropertiesRequestedEventArgs)
                Dim propertiesObject As CustomProjectProperties = Nothing
    
                ' If the properties object already exists, get it from the project's annotations.
                If False = e.Project.Annotations.TryGetValue(propertiesObject) Then
                    ' Otherwise, create a new properties object and add it to the annotations.
                    propertiesObject = New CustomProjectProperties(e.Project)
                    e.Project.Annotations.Add(propertiesObject)
                End If
    
                e.PropertySources.Add(propertiesObject)
            End Sub
        End Class
    
        Public Class CustomProjectProperties
            Private sharePointProject As ISharePointProject = Nothing
            Private Const MapImagesFolderPropertyDefaultValue As Boolean = False
            Private Const MapImagesFolderPropertyId = "ContosoMapImagesFolderProperty"
    
            Public Sub New(ByVal myProject As ISharePointProject)
                sharePointProject = myProject
            End Sub
    
            ' Represents the new boolean property MapImagesFolder.
            ' True = Map an Images folder to the project if one does not already exist; otherwise, do nothing.
            ' False = Remove the Images folder from the project, if one exists; otherwise, do nothing.
            <DisplayName("Map Images Folder")> _
            <DescriptionAttribute("Specifies whether an Images folder is mapped to the SharePoint project.")> _
            <DefaultValue(MapImagesFolderPropertyDefaultValue)> _
            Public Property MapImagesFolder As Boolean
                Get
                    Dim propertyStringValue As String = String.Empty
    
                    ' Try to get the current value from the .user file; if it does not yet exist, return a default value.
                    If Not sharePointProject.ProjectUserFileData.TryGetValue(MapImagesFolderPropertyId, propertyStringValue) Then
                        Return MapImagesFolderPropertyDefaultValue
                    Else
                        Return CBool(propertyStringValue)
                    End If
                End Get
    
                Set(ByVal value As Boolean)
                    If value Then
                        If Not ImagesMappedFolderInProjectExists(sharePointProject) Then
                            ' An Images folder is not mapped to the project, so map one.
                            Dim mappedFolder As IMappedFolder = sharePointProject.MappedFolders.Add(MappedFolderType.Images)
                            sharePointProject.ProjectService.Logger.WriteLine( _
                                mappedFolder.Name & " mapped folder added to the project.", LogCategory.Status)
                        End If
                    ElseIf (ImagesMappedFolderInProjectExists(sharePointProject) AndAlso UserSaysDeleteFile()) Then
                        ' An Images folder is mapped to the project and the user wants to remove it.
                        DeleteFolder()
                    End If
    
                    sharePointProject.ProjectUserFileData(MapImagesFolderPropertyId) = value.ToString()
                End Set
            End Property
    
            Private Function ImagesMappedFolderInProjectExists(ByVal sharePointProject As ISharePointProject) As Boolean
                Dim returnValue As Boolean = False
                For Each folder As IMappedFolder In sharePointProject.MappedFolders
                    ' Check to see if an Images folder is already mapped.
                    If (folder.FolderType = MappedFolderType.Images) Then
                        returnValue = True
                    End If
                Next
                Return returnValue
            End Function
    
            Private Function UserSaysDeleteFile() As Boolean
                ' Ask the user whether they want to delete the Images folder.
                Dim returnValue As Boolean = False
                If (MessageBox.Show("Do you want to delete the Images folder from the project?", _
                    "Delete the Images folder?", MessageBoxButtons.YesNo) = DialogResult.Yes) Then
                    returnValue = True
                End If
                Return returnValue
            End Function
    
            Private Sub DeleteFolder()
                ' The Visual Studio DTE object model is required to delete the mapped folder.
                Dim dteProject As EnvDTE.Project = _
                    sharePointProject.ProjectService.Convert(Of ISharePointProject, EnvDTE.Project)(sharePointProject)
                Dim targetFolderName As String = _
                    sharePointProject.MappedFolders.First(Function(mf) mf.FolderType = MappedFolderType.Images).Name
                Dim mappedFolderItem As EnvDTE.ProjectItem = dteProject.ProjectItems.Item(targetFolderName)
                mappedFolderItem.Delete()
    
                sharePointProject.ProjectService.Logger.WriteLine("Mapped Folder " & _
                    targetFolderName & " deleted", LogCategory.Status)
            End Sub
        End Class
    End Namespace
    
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.ComponentModel;
    using System.ComponentModel.Composition;
    using System.Windows.Forms;
    using Microsoft.VisualStudio.SharePoint;
    using EnvDTE;
    
    // Adds a new property called MapImagesFolder to any SharePoint project.
    // When MapImagesFolder is set to true, the Image folder is mapped to the project.
    // When MapImagesFolder is set to false, the Image folder is deleted from the project.
    namespace SP_Project_Extension
    {
        // Export attribute: Enables Visual Studio to discover and load this extension.
        [Export(typeof(ISharePointProjectExtension))]
    
        // Defines a new custom project property that applies to any SharePoint project.
        public class SPProjectExtension : ISharePointProjectExtension
        {
            // Implements ISharePointProjectService.Initialize, which determines the behavior of the new property.
            public void Initialize(ISharePointProjectService projectService)
            {
                // Handle events for when a project property is changed.
                projectService.ProjectPropertiesRequested +=
                    new EventHandler<SharePointProjectPropertiesRequestedEventArgs>(projectService_ProjectPropertiesRequested);
            }
    
            void projectService_ProjectPropertiesRequested(object sender, SharePointProjectPropertiesRequestedEventArgs e)
            {
                // Add a new property to the SharePoint project.
                e.PropertySources.Add((object)new ImagesMappedFolderProperty(e.Project));
            }
        }
    
        public class ImagesMappedFolderProperty
        {
            ISharePointProject sharePointProject = null;
            public ImagesMappedFolderProperty(ISharePointProject myProject)
            {
                sharePointProject = myProject;
            }
            static bool MapFolderSetting = false;
    
            [DisplayName("Map Images Folder")]
            [DescriptionAttribute("Specifies whether an Images folder is mapped to the SharePoint project.")]
            public bool MapImagesFolder
            // Represents the new boolean property MapImagesFolder.
            // True = Map an Images folder to the project if one does not already exist; otherwise, do nothing.
            // False = Remove the Images folder from the project, if one exists; otherwise, do nothing.
            {
                get
                {
                    // Get the current property value.
                    return MapFolderSetting;
                }
                set
                {
                    if (value)
                    {
                        if (!ImagesMappedFolderInProjectExists(sharePointProject))
                        {
                            // An Images folder is not mapped to the project, so map one.
                            IMappedFolder mappedFolder1 = sharePointProject.MappedFolders.Add(MappedFolderType.Images);
                            // Add a note to the logger that a mapped folder was added.
                            sharePointProject.ProjectService.Logger.WriteLine("Mapped Folder added:" + mappedFolder1.Name, LogCategory.Status);
                        }
                    }
                    else
                    {
                        if (ImagesMappedFolderInProjectExists(sharePointProject) && UserSaysDeleteFile())
                        {
                            // An Images folder is mapped to the project and the user wants to remove it.
                            // The Visual Studio DTE object model is required to delete the mapped folder.
                            // Reference the Visual Studio DTE model, get handles for the SharePoint project and project items.
                            EnvDTE.Project dteProject = sharePointProject.ProjectService.Convert<ISharePointProject, EnvDTE.Project>(sharePointProject);
                            string targetFolderName = sharePointProject.MappedFolders.First(mf => mf.FolderType == MappedFolderType.Images).Name;
                            EnvDTE.ProjectItem mappedFolderItem = dteProject.ProjectItems.Item(targetFolderName);
                            mappedFolderItem.Delete();
                            sharePointProject.ProjectService.Logger.WriteLine("Mapped Folder " + targetFolderName + " deleted", LogCategory.Status);
                        }
                    }
                    MapFolderSetting = value;
                }
    
            }
    
            private bool ImagesMappedFolderInProjectExists(ISharePointProject sharePointProject)
            {
                bool retVal = false;
                foreach (IMappedFolder folder in sharePointProject.MappedFolders)
                {
                    // Check to see if an Images folder is already mapped.
                    if (folder.FolderType == MappedFolderType.Images)
                        retVal = true;
                }
                return retVal;
            }
    
            private bool UserSaysDeleteFile()
            {
                // Prompt the user whether they want to delete the Images folder.
                bool retVal = false;
                if (MessageBox.Show("Do you want to delete the Images folder from the project?", "Delete the Images folder?", MessageBoxButtons.YesNo) == DialogResult.Yes)
                {
                    retVal = true;
                }
                return retVal;
    
            }
        }
    }
    

建置方案

接下來,建置方案,以確定專案在編譯時未發生任何錯誤。

若要建置方案

  • 在 [建置] 功能表上,按一下 [建置方案]。

建立 VSIX 套件以部署專案屬性擴充功能

若要部署專案擴充功能,請在您的方案中使用 VSIX 專案,以建立 VSIX 套件。 首先,修改 VSIX 專案包含的 source.extension.vsixmanifest 檔案,來設定 VSIX 套件。 接著,建置方案來建立 VSIX 套件。

若要設定和建立 VSIX 套件

  1. 在 [方案總管] 中,按兩下 [source.extension.vsixmanifest] 檔。

    Visual Studio 會在資訊清單編輯器中開啟檔案。 這個編輯器提供 UI,可用來編輯資訊清單中的 XML。 此資訊稍後顯示在 [擴充管理員] 中。所有 VSIX 套件都需要 extension.vsixmanifest 檔案。 如需這個檔案的詳細資訊,請參閱VSIX Extension Schema Reference

  2. 在 [專案名稱] 方塊中,輸入 Custom Project Property。

  3. 在 [作者] 方塊中,輸入 Contoso。

  4. 在 [說明] 方塊中輸入觸發將影像資源資料夾對應至專案的自訂 SharePoint 專案屬性。

  5. 在編輯器的 [內容] 區段中,按一下 [加入內容] 按鈕。

  6. 在 [選取內容類型] 下拉式方塊中,選取 [MEF 元件]。

    注意事項注意事項

    這個值對應於 extension.vsixmanifest 檔案中的 MEFComponent 項目。 這個項目指定 VSIX 套件中的擴充組件名稱。 如需詳細資訊,請參閱 MEFComponent Element (VSX Schema)

  7. 按一下 [選取來源] 區段中的 [專案] 選項,然後選取下拉式方塊中的 [ProjextExtension]。

    這個值會識別您在專案中建置的組件名稱。

  8. 完成後,請按一下 [確定] 並關閉 [加入內容] 對話方塊。

  9. 當您完成時,請按一下 [檔案] 功能表上的 [全部儲存],然後關閉此資訊清單設計器。

  10. 在 [建置] 功能表上,按一下 [建置方案]。 確定專案編譯時未發生錯誤。

  11. 按一下 [方案總管] 中的 ProjectExtensionPackage 專案,按一下 [顯示所有檔案] 按鈕,然後開啟 ProjectExtensionPackage 專案的建置輸出資料夾。 此資料夾現在應包含名為 ProjectExtensionPackage.vsix 的檔案。

    根據預設,建置輸出資料夾為 .. \bin\Debug 資料夾,其位於專案檔案包含的資料夾下。

測試專案屬性

您現在可以測試自訂專案屬性。 最簡單的方式是在 Visual Studio 的實驗執行個體中偵錯和測試新專案屬性擴充功能。 這是在執行 VSIX 或其他擴充專案時建立的 Visual Studio 執行個體。 偵錯專案之後,您可以在系統上安裝擴充功能,然後繼續在 Visual Studio 的一般執行個體中對其進行偵錯和測試。

若要在 Visual Studio 的實驗執行個體中對擴充功能進行偵錯和測試

  1. 使用系統管理員認證重新啟動 Visual Studio,並開啟 ProjectExtensionPackage 方案。

  2. F5 啟動專案的偵錯版。

    Visual Studio 會將擴充功能安裝至 %UserProfile%\AppData\Local\Microsoft\VisualStudio\10.0Exp\Extensions\Contoso\Custom Project Property\1.0,並啟動 Visual Studio 的實驗執行個體。

  3. 在 Visual Studio 的實驗執行個體中,建立新的陣列方案 SharePoint 專案,例如「模組」。 對於精靈中的其他值,請使用預設值。

  4. 按一下 [方案總管] 中的專案節點。

    新的自訂屬性 [對應影像資料夾] 出現在 [屬性] 視窗中,並且預設值為 False。

  5. 將 [對應影像資料夾] 變更為 True。

    [影像] 資源資料夾隨即加入至 SharePoint 專案。

  6. 將 [對應影像資料夾] 變更為 False。

    [影像] 資源資料夾隨即從 SharePoint 專案刪除。

  7. 關閉 Visual Studio 的實驗執行個體。

請參閱

其他資源

擴充 SharePoint 專案

HOW TO:將屬性加入至 SharePoint 專案

在 SharePoint 專案系統類型與其他 Visual Studio 專案類型之間轉換

儲存 SharePoint 專案系統擴充功能的資料

讓自訂資料與 SharePoint 工具擴充功能產生關聯