このチュートリアルでは、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 2010 SDK。 このチュートリアルでは、プロジェクト プロパティ拡張機能を配置するための VSIX パッケージを、SDK の VSIX プロジェクト テンプレートを使用して作成します。 詳細については、「Visual Studio の SharePoint ツールの拡張」を参照してください。
プロジェクトの作成
このチュートリアルを完了するには、2 つのプロジェクトを作成する必要があります。
プロジェクトの拡張機能を配置するために VSIX パッケージを作成する VSIX プロジェクト
プロジェクトの拡張機能を実装するクラス ライブラリ プロジェクト
この 2 つのプロジェクトを作成することから始めます。
VSIX プロジェクトを作成するには
Visual Studio を起動します。
[ファイル] メニューの [新規作成] をポイントし、[プロジェクト] をクリックします。
[新しいプロジェクト] ダイアログ ボックスで、[Visual C#] ノードまたは [Visual Basic] ノードを展開し、[機能拡張] ノードをクリックします。
注意
[機能拡張] ノードは、Visual Studio 2010 SDK がインストールされている場合にのみ利用できます。 詳細については、このトピックで前に説明した「前提条件」を参照してください。
ダイアログ ボックス上部のコンボ ボックスで、[.NET Framework 4] をクリックします。 SharePoint ツールの拡張機能を使用するには、このバージョンの .NET Framework の機能が必要です。
[VSIX プロジェクト] テンプレートをクリックします。
[名前] ボックスに「ProjectExtensionPackage」と入力します。
[OK] をクリックします。
Visual Studio のソリューション エクスプローラーに ProjectExtensionPackage プロジェクトが追加されます。
拡張機能プロジェクトを作成するには
ソリューション エクスプローラーでソリューション ノードを右クリックし、[追加] をクリックして [新しいプロジェクト] をクリックします。
注意
Visual Basic プロジェクトでは、[全般] ([オプション] ダイアログ ボックス - [プロジェクトおよびソリューション]) の [常にソリューションを表示] チェック ボックスがオンになっている場合にのみ、ソリューション エクスプローラーにソリューション ノードが表示されます。
[新しいプロジェクト] ダイアログ ボックスで、[Visual C#] ノードまたは [Visual Basic] ノードを展開し、[Windows] をクリックします。
ダイアログ ボックス上部のコンボ ボックスで、[.NET Framework 4] を選択します。
[クラス ライブラリ] プロジェクト テンプレートを選択します。
[名前] ボックスに「ProjectExtension」と入力します。
[OK] をクリックします。
Visual Studio によって、ProjectExtension プロジェクトがソリューションに追加され、既定の Class1 コード ファイルが開きます。
Class1 コード ファイルをプロジェクトから削除します。
プロジェクトの構成
プロジェクトの拡張機能を作成するためのコードを記述する前に、コード ファイルおよびアセンブリ参照を拡張機能プロジェクトに追加します。
プロジェクトを構成するには
CustomProperty という名前の新しいコード ファイルを ProjectExtension プロジェクトに追加します。
[プロジェクト] メニューの [参照の追加] をクリックします。
[.NET] タブで、Ctrl キーを押しながら次のアセンブリをクリックし、[OK] をクリックします。
Microsoft.VisualStudio.SharePoint
System.ComponentModel.Composition
System.Windows.Forms
EnvDTE
ソリューション エクスプローラーで、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 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 パッケージを構成および作成するには
ソリューション エクスプローラーで、source.extension.vsixmanifest ファイルをダブルクリックします。
Visual Studio によってマニフェスト エディターでファイルが開きます。 このエディターには、マニフェスト内の XML を編集するための UI が備わっています。 この情報は後で拡張機能マネージャーに表示されます。extension.vsixmanifest ファイルは、すべての VSIX パッケージで必要となります。 このファイルの詳細については、「VSIX Extension Schema Reference」を参照してください。
[製品名] ボックスに「Custom Project Property」と入力します。
[作成者] ボックスに「Contoso」と入力します。
[説明] ボックスに「Images リソース フォルダーのプロジェクトへのマッピングを切り替えるカスタム SharePoint プロジェクト プロパティ」と入力します。
エディターの [コンテンツ] セクションで、[コンテンツの追加] をクリックします。
[コンテンツ タイプの選択] ボックスの一覧の [MEF コンポーネント] をクリックします。
注意
この値は、extension.vsixmanifest ファイル内の MEFComponent 要素に対応します。 VSIX パッケージ内の拡張機能アセンブリの名前がこの要素によって指定されます。 詳細については、「MEFComponent Element (VSX Schema)」を参照してください。
[ソースの選択] セクションで、[プロジェクト] オプションをクリックし、ドロップダウン ボックスで [ProjextExtension] をクリックします。
この値は、プロジェクトで構築しているアセンブリの名前を指定します。
操作を終了したら、[OK] をクリックし、[コンテンツの追加] ダイアログ ボックスを閉じます。
操作を終了したら、[ファイル] メニューの [すべてを保存] をクリックし、マニフェスト デザイナーを閉じます。
[ビルド] メニューの [ソリューションのビルド] をクリックします。 エラーが発生することなくプロジェクトがコンパイルされることを確認します。
ソリューション エクスプローラーで ProjectExtensionPackage プロジェクトをクリックし、[すべてのファイルを表示] をクリックします。その後、ProjectExtensionPackage プロジェクトのビルド出力フォルダーを開きます。 これで、このフォルダーに ProjectExtensionPackage.vsix という名前のフォルダーが格納されます。
既定では、プロジェクト ファイルに格納されているフォルダー の ..\bin\Debug フォルダーがビルド出力フォルダーです。
プロジェクト プロパティのテスト
これで、カスタム プロジェクト プロパティをテストする準備ができました。 It is easiest to debug and test the new project property extension in an experimental instance of Visual Studio の実験用のインスタンスで新しいプロジェクト プロパティの拡張機能のデバッグとテストを行うのが最も簡単です。 これは、VSIX または他の機能拡張プロジェクトを実行するときに登録される Visual Studio のインスタンスです。 プロジェクトをデバッグした後、拡張機能をシステムにインストールし、Visual Studio の通常のインスタンスで拡張機能のデバッグとテストを続行することができます。
Visual Studio の実験用のインスタンスで拡張機能のデバッグとテストを行うには
管理者の資格情報を使用して Visual Studio を再起動し、ProjectExtensionPackage ソリューションを開きます。
F5 キーを押し、プロジェクトのデバッグ ビルドを開始します。
Visual Studio によって、拡張機能が %UserProfile%\AppData\Local\Microsoft\VisualStudio\10.0Exp\Extensions\Contoso\Custom Project Property\1.0 にインストールされ、Visual Studio の実験用のインスタンスが開始されます。
Visual Studio の実験用のインスタンスで、モジュールなどの新しいファーム ソリューション SharePoint プロジェクトを作成します。 ウィザードの他の値については既定値を使用します。
ソリューション エクスプローラーで、プロジェクト ノードをクリックします。
[プロパティ] ウィンドウに、既定値が False である新しいカスタム プロパティ Map Images Folder が表示されます。
Map Images Folder を True に変更します。
SharePoint プロジェクトに Images リソース フォルダーが追加されます。
Map Images Folder を False に変更します。
SharePoint プロジェクトから Images リソース フォルダーが削除されます。
Visual Studio の実験用のインスタンスを閉じます。
参照
その他の技術情報
方法: SharePoint プロジェクトにプロパティを追加する
SharePoint プロジェクト システムと他の Visual Studio プロジェクトの間の型変換