このチュートリアルでは、SharePoint プロジェクトの拡張機能を作成する方法について説明します。プロジェクトが追加、削除、または名前変更されたときにプロジェクト レベルのイベント (など) に応答のプロジェクトの拡張機能を使用できます。また、プロパティ値の変更時にカスタム プロパティを追加したり、応答したりすることもできます。プロジェクト項目の拡張機能とは異なり、プロジェクトの拡張機能を特定の SharePoint プロジェクトの種類に関連付けることはできません。プロジェクトの拡張機能を作成すると、いずれかの種類の SharePoint プロジェクトが Visual Studio で開かれたときに、その拡張機能が読み込まれます。
このチュートリアルでは、Visual Studio で作成された SharePoint プロジェクトに追加するカスタムのブール型プロパティを作成します。True に設定すると、新しいプロパティによって Images リソース フォルダーがプロジェクトに追加されるか、マップされます。False に設定すると、Images フォルダーがある場合には、そのフォルダーが削除されます。詳細については、「方法: マップされたフォルダーを追加および削除する」を参照してください。
このチュートリアルでは、次のタスクを実行します。
次の処理を行う SharePoint プロジェクトの Visual Studio 拡張機能を作成する。
カスタム プロジェクト プロパティを [プロパティ] ウィンドウに追加します。追加したプロパティが SharePoint プロジェクトに適用されます。
SharePoint プロジェクトのオブジェクト モデルを使用して、マップされたフォルダーをプロジェクトに追加します。
Visual Studio のオートメーション オブジェクト モデル (DTE) を使用して、マップされたフォルダーをプロジェクトから削除します。
プロジェクト プロパティの拡張機能のアセンブリを配置するための Visual Studio Visual Studio Extension (VSIX) パッケージを構築する。
プロジェクト プロパティのデバッグとテストを行う。
必須コンポーネント
このチュートリアルを実行するには、開発コンピューターに次のコンポーネントが必要です。
サポート対象エディションの Microsoft Windows、SharePoint、Visual Studio。詳細については、「SharePoint ソリューションの開発要件」を参照してください。
Visual Studio SDK。このチュートリアルでは、プロジェクト プロパティ拡張機能を配置するための VSIX パッケージを、SDK の VSIX プロジェクト テンプレートを使用して作成します。詳細については、「Visual Studio の SharePoint ツールの拡張」を参照してください。
プロジェクトの作成
このチュートリアルを完了するには、2 つのプロジェクトを作成する必要があります。
プロジェクトの拡張機能を配置するために VSIX パッケージを作成する VSIX プロジェクト
プロジェクトの拡張機能を実装するクラス ライブラリ プロジェクト
この 2 つのプロジェクトを作成することから始めます。
VSIX プロジェクトを作成するには
Visual Studio を起動します。
メニュー バーで [ファイル]、[新規]、[プロジェクト] の順にクリックします。
[新しいプロジェクト] のダイアログ ボックスで、[Visual C#] または [Visual Basic] のノードを展開し、[機能拡張] のノードを選択します。
[!メモ]
このノードは、Visual Studio SDKをインストールするときだけです。詳細については、このトピックで前に説明した「前提条件」を参照してください。
ダイアログ ボックスの上部に、.NET Frameworkのバージョンの一覧の [.NET Framework 4.5] を選択し、[VSIX プロジェクト] テンプレートを選択します。
[名前] ボックスに、[ProjectExtensionPackage]を入力し、を [OK] のボタンをクリックします。
[ProjectExtensionPackage] のプロジェクトは **[ソリューション エクスプローラー]**に表示されます。
拡張機能プロジェクトを作成するには
**[ソリューション エクスプローラー]で、ソリューション ノードのショートカット メニューを開き、[追加]**を選択し、を **[新しいプロジェクト]**を選択します。
[!メモ]
Visual Basic のプロジェクトでは、ソリューション ノードが [ソリューション エクスプローラー] で [常にソリューションを表示] のチェック ボックスが General, Projects and Solutions, Options Dialog Boxで選択されている場合にのみ表示されます。
[新しいプロジェクト] のダイアログ ボックスで、[Visual C#] または [Visual Basic] のノードを展開し、**[ウィンドウ]**を選択します。
ダイアログ ボックスの上部に、.NET Frameworkのバージョンの一覧の [.NET Framework 4.5] を選択し、[クラス ライブラリ] のプロジェクト テンプレートを選択します。
[名前] ボックスに、[ProjectExtension]を入力し、を [OK] のボタンをクリックします。
Visual Studio によって、ProjectExtension プロジェクトがソリューションに追加され、既定の Class1 コード ファイルが開きます。
Class1 コード ファイルをプロジェクトから削除します。
プロジェクトの構成
プロジェクトの拡張機能を作成するためのコードを記述する前に、コード ファイルおよびアセンブリ参照を拡張機能プロジェクトに追加します。
プロジェクトを構成するには
ProjectExtensionプロジェクトへの CustomProperty という名前のコード ファイルを追加します。
[ProjectExtension] のプロジェクトのショートカット メニューを開き、**[参照の追加]**を選択します。
[CustomPropertyマネージャー–を参照してください。] のダイアログ ボックスで、[Framework] のノードを選択し、System.ComponentModel.CompositionおよびSystem.Windows.Formsの各アセンブリの横にあるチェック ボックスをオンにします。
[拡張機能] のノードを選択すると、Microsoft.VisualStudio.SharePoint EnvDTEアセンブリの横にあるチェック ボックスをオンにし、[OK] のボタンをクリックします。
[ProjectExtension] のプロジェクトの [参照] フォルダーの下の **[ソリューション エクスプローラー]では、[EnvDTE]**を選択します。
[プロパティ] ウィンドウで、[相互運用型の埋め込み] プロパティを False に変更します。
新しい SharePoint プロジェクト プロパティの定義
プロジェクトの拡張機能および新しいプロジェクト プロパティの動作を定義するクラスを作成します。新しいプロジェクトの拡張機能を定義するため、このクラスに ISharePointProjectExtension インターフェイスを実装します。このインターフェイスは、SharePoint プロジェクトの拡張機能を定義する場合に必ず実装します。さらに、このクラスに ExportAttribute メソッドを追加します。この属性によって、Visual Studio は ISharePointProjectExtension の実装を検出し、読み込むことができます。この属性のコンストラクターには ISharePointProjectExtension 型を渡します。
新しい SharePoint プロジェクト プロパティを定義するには
CustomPropertyコード ファイルに次のコードを貼り付けます。
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 Namespaceusing 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 パッケージを構成および作成するには
[ソリューション エクスプローラー]では、source.extension.vsixmanifestファイルのショートカット メニューを開き、[開く] のボタンをクリックします。
Visual Studio はマニフェスト デザイナーでファイルを開きます。[メタデータ] のタブで、表示される情報は **[拡張機能と更新プログラム]**に表示されます。すべてのVSIXパッケージは、extension.vsixmanifestファイルが必要です。このファイルの詳細については、「VSIX 拡張機能のスキーマに関するリファレンス」を参照してください。
[製品名] ボックスに、カスタム プロジェクト プロパティを入力します。
[作成者] ボックスに、[Contoso]を入力します。
[説明] ボックスに、プロジェクトにイメージ リソースのフォルダー マップを切り替えるカスタムのSharePointプロジェクト プロパティを入力します。
[資産] のタブをクリックし、[新規作成] のボタンをクリックします。
[新しい資産の追加] のダイアログ ボックスが表示されます。
[種類] の一覧で、**[Microsoft.VisualStudio.MefComponent]**を選択します。
[!メモ]
この値は、extension.vsixmanifest ファイル内の MEFComponent 要素に対応します。この要素は、VSIX パッケージ内の拡張機能アセンブリの名前を指定します。詳細については、「MEFComponent Element」を参照してください。
[ソース] の一覧で、[現在のソリューション内のプロジェクト] のオプション ボタンを選択します。
[プロジェクト] の一覧で、[ProjectExtension]を選択します。
この値は、プロジェクトでビルドされたアセンブリの名前を指定します。
[新しい資産の追加] のダイアログ ボックスを閉じるに [OK] を選択します。
メニュー バーで、終了選択し、マニフェスト デザイナーを閉じるとき [ファイル]、を [すべて保存]。
メニュー バーで、[ビルド]、**[ソリューションのビルド]**を選択し、次に、プロジェクトがエラーなしでコンパイルしてください。
[ソリューション エクスプローラー]では、[ProjectExtensionPackage] のプロジェクトのショートカット メニューを開き、[エクスプローラーでフォルダーを開く] のボタンをクリックします。
**[エクスプローラー]**では、ProjectExtensionPackageプロジェクトのビルド出力フォルダーを開き、フォルダーがProjectExtensionPackage.vsixという名前のファイルが含まれていることを確認します。
既定では、プロジェクト ファイルに格納されているフォルダーの ..\bin\Debug フォルダーがビルド出力フォルダーです。
プロジェクト プロパティのテスト
カスタム プロジェクト プロパティをテストする準備ができました。Visual Studioの実験用インスタンスで新しいプロジェクト プロパティの拡張機能のデバッグ、テストが容易になります。Visual Studio のこのインスタンスは、VSIXまたは他の機能拡張プロジェクトを実行するときに作成されます。プロジェクトをデバッグした後、拡張機能をシステムにインストールされて、Visual Studioの通常のインスタンスで拡張デバッグとテストを行うことができます。
Visual Studio の実験用のインスタンスで拡張機能のデバッグとテストを行うには
管理資格情報を使用してを Visual Studio を再起動し、ProjectExtensionPackageソリューションを開きます。
[F5] のキーを選択して、プロジェクトのデバッグ ビルドをまたは、**[デバッグ]**を選択するメニュー バーで **[デバッグの開始]**起動します。
Visual Studio は%UserProfile%\AppData\Local\Microsoft\VisualStudio\11.0Exp\Extensions\Contoso\CustomのプロジェクトProperty\1.0に拡張機能をインストール、Visual Studioの実験用インスタンスを起動します。
Visual Studioの実験用インスタンスで、ファーム ソリューションのSharePointプロジェクトを作成し、そのほかの値のウィザードで既定値を使用します。
メニュー バーで [ファイル]、[新規]、[プロジェクト] の順にクリックします。
[新しいプロジェクト] のダイアログ ボックスの上部に、.NET Frameworkのバージョンの [.NET Framework 3.5] リストのを選択します。
SharePointツールの拡張機能が .NET Framework、このバージョンのの機能が必要です。
[テンプレート] のノードの下で、[Visual C#] または [Visual Basic] のノードを展開し、[SharePoint] のノードを選択し、を [2010] のノードを選択します。
[SharePoint 2010 プロジェクト] テンプレートを選択し、プロジェクトの名前として [ModuleTest] を入力します。
[ソリューション エクスプローラー]では、[ModuleTest] のプロジェクト ノードを選択します。
[プロパティ] ウィンドウに、既定値が False である新しいカスタム プロパティ Map Images Folder が表示されます。
Trueにそのプロパティの値を変更します。
SharePoint プロジェクトに Images リソース フォルダーが追加されます。
Falseにそのプロパティの値を返します。
[Delete the Images folder?] のダイアログ ボックスの [○] のボタンを選択すると、Imagesリソース フォルダーがSharePointプロジェクトから削除されます。
Visual Studio の実験用のインスタンスを閉じます。
参照
概念
方法: SharePoint プロジェクトにプロパティを追加する
SharePoint プロジェクト システムと他の Visual Studio プロジェクトの間の型変換