연습: 프로젝트 템플릿을 사용하여 사이트 열 프로젝트 항목 만들기, 2부
Visual Studio에서 SharePoint 프로젝트 항목의 사용자 지정 형식을 정의하여 프로젝트 템플릿과 연결한 후에는 템플릿에 대한 마법사를 제공할 수 있습니다.마법사를 사용하면 사용자가 템플릿을 사용하여 해당 프로젝트 항목이 포함된 새 프로젝트를 만들 때 사용자에게서 정보를 수집할 수 있습니다.수집한 정보는 프로젝트 항목을 초기화하는 데 사용될 수 있습니다.
이 연습에서는 연습: 프로젝트 템플릿을 사용하여 사이트 열 프로젝트 항목 만들기, 1부에서 설명한 사이트 열 프로젝트 템플릿에 마법사를 추가합니다.사용자가 사이트 열 프로젝트를 만들 때 마법사에서는 사이트 열에 대한 정보(예: 기본 형식 및 그룹)를 수집하고 이 정보를 새 프로젝트의 Elements.xml 파일에 추가합니다.
이 연습에서는 다음 작업을 수행합니다.
프로젝트 템플릿과 연결된 사용자 지정 SharePoint 프로젝트 항목 형식을 위한 마법사 만들기
사용자 지정 마법사 Visual Studio SharePoint 프로젝트에 대 한 기본 마법사와 비슷한 UI를 정의 합니다.
마법사가 실행되는 동안 로컬 SharePoint 사이트를 호출하는 데 사용되는 두 가지 SharePoint 명령 만들기.SharePoint 명령은 Visual Studio 확장이 SharePoint 서버 개체 모델에서 API를 호출하기 위해 사용할 수 있는 메서드입니다.자세한 내용은 SharePoint 개체 모델 호출을 참조하십시오.
대체 가능한 매개 변수를 사용하여 마법사에서 수집한 데이터로 SharePoint 프로젝트 파일 초기화
각각의 새 사이트 열 프로젝트 인스턴스에서 .snk 파일 새로 만들기이 파일은 SharePoint 솔루션 어셈블리가 전역 어셈블리 캐시에 배포될 수 있도록 프로젝트 출력에 서명하는 데 사용됩니다.
마법사 디버깅 및 테스트
[!참고]
https://go.microsoft.com/fwlink/?LinkId=191369에서 이 연습에 대한 완료된 프로젝트, 코드 및 기타 파일이 포함된 샘플을 다운로드할 수 있습니다.
사전 요구 사항
이 연습을 수행하려면 먼저 연습: 프로젝트 템플릿을 사용하여 사이트 열 프로젝트 항목 만들기, 1부를 완료하여 SiteColumnProjectItem 솔루션을 만들어야 합니다.
또한 개발 컴퓨터에 다음 구성 요소가 있어야 이 연습을 완료할 수 있습니다.
지원 되는 버전의 Windows, SharePoint 및 Visual Studio.자세한 내용은 SharePoint 솔루션 개발 요구 사항을 참조하십시오.
Visual Studio SDK입니다.이 연습에서는 SDK의 VSIX 프로젝트 템플릿을 사용하여 프로젝트 항목을 배포하기 위한 VSIX 패키지를 만듭니다.자세한 내용은 Visual Studio에서 SharePoint 도구 확장을 참조하십시오.
다음 개념을 알고 있으면 연습을 완료하는 데 도움이 되지만 반드시 필요하지는 않습니다.
Visual Studio의 프로젝트 마법사 및 항목 템플릿 마법사.자세한 내용은 방법: 프로젝트 템플릿에 마법사 사용 및 IWizard 인터페이스를 참조하십시오.
SharePoint의 사이트 열.자세한 내용은 Columns를 참조하십시오.
마법사 구성 요소 이해
이 연습에서 보여 주는 마법사에는 몇 가지 구성 요소가 포함되어 있습니다.다음 표에서는 이러한 구성 요소에 대해 설명합니다.
구성 요소 |
설명 |
---|---|
마법사 구현 |
IWizard 인터페이스를 구현하는 SiteColumnProjectWizard라는 클래스입니다.이 인터페이스는 마법사가 시작되고 완료될 때와 마법사 실행 중의 특정한 때에 Visual Studio에서 호출하는 메서드를 정의합니다. |
마법사 UI |
WizardWindow라는 WPF 기반 창입니다.이 창에는 Page1 및 Page2라는 두 가지 사용자 정의 컨트롤이 포함되어 있습니다.이러한 사용자 정의 컨트롤은 마법사의 두 페이지를 나타냅니다. 이 연습에서 마법사 구현의 RunStarted 메서드는 마법사 UI를 표시합니다. |
마법사 데이터 모델 |
마법사 UI와 마법사 구현 간의 계층을 제공하는 SiteColumnWizardModel이라는 중간 클래스입니다.이 샘플에서는 이 클래스를 사용하여 마법사 구현과 마법사 UI를 서로 추상화합니다. 이 클래스는 모든 마법사의 필수 구성 요소가 아닙니다. 이 연습에서 마법사 구현은 마법사 UI를 표시할 때 SiteColumnWizardModel 개체를 마법사 창에 전달합니다.마법사 UI는 이 개체의 메서드를 사용하여 UI의 컨트롤 값을 저장하고 입력 사이트 URL이 유효한지 확인하는 등의 작업을 수행합니다.사용자가 마법사를 완료한 후 마법사 구현은 SiteColumnWizardModel 개체를 사용하여 UI의 최종 상태를 확인합니다. |
프로젝트 서명 관리자 |
마법사 구현이 각각의 새 프로젝트 인스턴스에서 key.snk 파일을 새로 만드는 데 사용하는 ProjectSigningManager라는 도우미 클래스입니다. |
SharePoint 명령 |
마법사가 실행되는 동안 마법사 데이터 모델에서 로컬 SharePoint 사이트를 호출하는 데 사용하는 메서드입니다.SharePoint 명령이 .NET Framework 3.5를 대상으로 해야 하기 때문에 이러한 명령은 마법사 코드의 나머지 부분과 다른 어셈블리에서 구현됩니다. |
프로젝트 만들기
이 연습을 완료하려면 연습: 프로젝트 템플릿을 사용하여 사이트 열 프로젝트 항목 만들기, 1부에서 만든 SiteColumnProjectItem 솔루션에 몇 가지 프로젝트를 추가해야 합니다.
WPF 프로젝트.이 프로젝트에서 IWizard 인터페이스를 구현하고 마법사 UI를 정의합니다.
SharePoint 명령을 정의하는 클래스 라이브러리 프로젝트.이 프로젝트는 .NET Framework 3.5를 대상으로 해야 합니다.
먼저 프로젝트를 만들어 연습을 시작합니다.
WPF 프로젝트를 만들려면
Visual Studio, SiteColumnProjectItem 솔루션을 엽니다.
솔루션 탐색기, 바로 가기 메뉴를 열고를 SiteColumnProjectItem 솔루션 노드를 선택 추가, 다음 선택 새 프로젝트.
[!참고]
Visual Basic 프로젝트에서는 General, Projects and Solutions, Options Dialog Box에서 솔루션 항상 표시 확인란을 선택한 경우에만 솔루션 노드가 표시됩니다.
상단에 있는 새 프로젝트 추가 대화 상자에서 있는지 확인 하십시오 .NET Framework 4.5 .NET Framework 버전의 목록에서 선택 됩니다.
확장은 C# 노드 또는 Visual Basic 노드를 선택 하 고 있는 Windows 노드.
프로젝트 템플릿 목록에서 선택 WPF 사용자 컨트롤 라이브러리, 프로젝트의 이름을 ProjectTemplateWizard, 다음 선택은 확인 단추입니다.
Visual Studio추가 된 ProjectTemplateWizard 프로젝트를 솔루션 및 기본 UserControl1.xaml 파일을 엽니다.
프로젝트에서 UserControl1.xaml 파일을 삭제합니다.
SharePoint 명령 프로젝트를 만들려면
솔루션 탐색기, SiteColumnProjectItem 솔루션 노드에 대 한 바로 가기 메뉴를 열고 추가, 다음 선택 새 프로젝트.
상단에는 새 프로젝트 추가 대화 상자에서 선택 .NET Framework 3.5 .NET Framework 버전의 목록에서입니다.
확장 된 C# 노드 또는 Visual Basic 노드를 다음 선택은 Windows 노드.
선택은 클래스 라이브러리 : 프로젝트 이름, 프로젝트 템플릿 SharePointCommands, 다음 선택은 확인 단추.
Visual Studio추가 된 SharePointCommands 프로젝트를 솔루션 및 기본 Class1 코드 파일을 엽니다.
프로젝트에서 Class1 코드 파일을 삭제합니다.
프로젝트 구성
마법사를 만들기 전에 일부 코드 파일과 어셈블리 참조를 프로젝트에 추가 해야 합니다.
마법사 프로젝트를 구성하려면
솔루션 탐색기, 바로 가기 메뉴를 열고를 ProjectTemplateWizard 프로젝트 노드 및 다음 선택 속성.
에 프로젝트 디자이너, 선택의 응용 프로그램 C# 프로젝트에 대 한 탭 또는 컴파일 Visual Basic 프로젝트에 대 한 탭입니다.
.NET Framework 4.5.NET Framework 4.5 클라이언트 프로필이 아닌 대상 프레임 워크 설정 되어 있는지 확인 하십시오.
자세한 내용은 방법: 한 버전의 .NET Framework를 대상으로 지정을 참조하십시오.
바로 가기 메뉴를 열고는 ProjectTemplateWizard 선택, 프로젝트 추가, 다음 선택 새 항목.
선택은 창 (WPF) : 항목 이름, 항목 WizardWindow, 다음 선택은 추가 단추.
두 개의 추가 사용자 컨트롤 (WPF) 항목을 프로젝트에 하 고 이름을 1 페이지 및 2 페이지.
네 코드 파일을 프로젝트에 추가 하 고 다음 이름 들이므로.
SiteColumnProjectWizard
SiteColumnWizardModel
ProjectSigningManager
CommandIds
바로 가기 메뉴를 열고를 ProjectTemplateWizard 프로젝트 노드 및 다음 선택 참조 추가.
확장은 어셈블리 노드를 선택 된 확장 노드 및 다음 다음 어셈블리 옆에 있는 확인란을 선택:
EnvDTE
Microsoft.VisualStudio.OLE.Interop
Microsoft.VisualStudio.SharePoint
Microsoft.VisualStudio.Shell.11.0
Microsoft.VisualStudio.Shell.Interop.10.0
Microsoft.VisualStudio.Shell.Interop.11.0
Microsoft.VisualStudio.TemplateWizardInterface
선택은 확인 어셈블리를 프로젝트에 추가 하는 단추입니다.
솔루션 탐색기아래에서 참조 폴더에는 ProjectTemplateWizard 프로젝트를 선택 EnvDTE.
[!참고]
Visual Basic 프로젝트에서는 General, Projects and Solutions, Options Dialog Box에서 솔루션 항상 표시 확인란을 선택한 경우에만 참조 폴더가 표시됩니다.
에 속성 창에서 값을 변경의 Interop 형식 포함 속성을 False.
Visual Basic 프로젝트를 개발 하는 경우 가져오기는 ProjectTemplateWizard 네임 스페이스를 사용 하 여 프로젝트에 있는 프로젝트 디자이너.
자세한 내용은 방법: 가져온 네임스페이스 추가 또는 제거(Visual Basic)을 참조하십시오.
SharePointCommands 프로젝트를 구성하려면
솔루션 탐색기, 선택은 SharePointCommands 프로젝트 노드.
메뉴 표시줄에서 선택 프로젝트, 기존 항목 추가.
에 기존 항목 추가 대화 상자 ProjectTemplateWizard 프로젝트에 대 한 코드 파일이 들어 있는 폴더를 찾은 다음 선택은 CommandIds 코드 파일입니다.
옆에 있는 화살표를 선택한는 추가 단추를 클릭 한 다음 선택은 링크로 추가 표시 된 메뉴에서 옵션을.
Visual Studio코드 파일에 추가 된 SharePointCommands 프로젝트에 링크로.코드 파일은 ProjectTemplateWizard 프로젝트, 하지만 파일의 코드 또한 컴파일할에서 SharePointCommands 프로젝트.
에 SharePointCommands 프로젝트에 명령 이라고 하는 다른 코드 파일을 추가 합니다.
SharePointCommands 프로젝트를 선택 하 고 메뉴 표시줄에서 선택 프로젝트, 참조 추가.
확장은 어셈블리 노드를 선택 된 확장 노드 및 다음 다음 어셈블리 옆에 있는 확인란을 선택:
Microsoft.SharePoint
Microsoft.VisualStudio.SharePoint.Commands
선택은 확인 어셈블리를 프로젝트에 추가 하는 단추입니다.
마법사 모델, 서명 관리자 및 SharePoint 명령 ID 만들기
샘플에서 다음 구성 요소를 구현하는 코드를 ProjectTemplateWizard 프로젝트에 추가합니다.
SharePoint 명령 ID.이러한 문자열 마법사를 사용 하 여 SharePoint 명령을 식별 합니다.이 연습의 뒷부분에서 명령을 구현 하는 SharePointCommands 프로젝트에 코드를 추가 합니다.
마법사 데이터 모델
프로젝트 서명 관리자
이러한 구성 요소에 대한 자세한 내용은 마법사 구성 요소 이해를 참조하십시오.
SharePoint 명령 ID를 정의하려면
ProjectTemplateWizard 프로젝트 CommandIds 코드 파일을 열고이 파일의 전체 내용을 다음 코드로 대체 합니다.
Namespace Contoso.SharePoint.Commands Public Class CommandIds Public Const GetFieldTypes As String = "Contoso.Commands.GetFieldTypes" Public Const ValidateSite As String = "Contoso.Commands.ValidateSite" End Class End Namespace
namespace Contoso.SharePoint.Commands { public static class CommandIds { public const string GetFieldTypes = "Contoso.Commands.GetFieldTypes"; public const string ValidateSite = "Contoso.Commands.ValidateSite"; } }
마법사 모델을 만들려면
SiteColumnWizardModel 코드 파일을 열고이 파일의 전체 내용을 다음 코드로 대체 합니다.
Imports EnvDTE Imports Microsoft.VisualStudio.SharePoint Imports Microsoft.VisualStudio Imports Microsoft.VisualStudio.Shell Imports Microsoft.VisualStudio.Shell.Interop Imports IOleServiceProvider = Microsoft.VisualStudio.OLE.Interop.IServiceProvider Public Class SiteColumnWizardModel Private dteObject As DTE Private projectServiceValue As ISharePointProjectService Private validatedUrls As New List(Of String) Friend Sub New(ByVal dteObject As DTE, ByVal requiresFarmPriveleges As Boolean) Me.dteObject = dteObject ' Initialize default values for wizard choices. IsSandboxed = Not requiresFarmPriveleges IsSecondPagePopulated = False FieldType = "Text" FieldGroup = "Custom Columns" FieldName = "My Custom Column" CurrentSiteUrl = GetLocalHostUrl() End Sub #Region "Helper methods used by the wizard UI" ' Specifies whether the current site URL is valid. Uses the ValidateSite SharePoint command to do this. Friend Function ValidateCurrentUrl(ByVal errorMessage As String) As Boolean Dim isValid As Boolean = False errorMessage = String.Empty If validatedUrls.Contains(CurrentSiteUrl) Then isValid = True Else Dim uriToValidate As Uri = New Uri(CurrentSiteUrl, UriKind.Absolute) Dim vsThreadedWaitDialog As IVsThreadedWaitDialog2 = Nothing Try vsThreadedWaitDialog = ShowProgressDialog("Connect to SharePoint", "Connecting to SharePoint site " + CurrentSiteUrl) isValid = Me.ProjectService.SharePointConnection.ExecuteCommand(Of Uri, Boolean)( Contoso.SharePoint.Commands.CommandIds.ValidateSite, uriToValidate) Catch ex As Exception errorMessage = "An error occurred while validating the site. " + ex.Message Finally If isValid Then validatedUrls.Add(CurrentSiteUrl) End If If vsThreadedWaitDialog IsNot Nothing Then CloseProgressDialog(vsThreadedWaitDialog) End If End Try End If Return isValid End Function ' Gets the available field types from the SharePoint site. Uses the GetFieldTypes SharePoint command to do this. Friend Function GetFieldTypes() As ArrayList ' If we have not yet validated this site, do it now. Dim errorMessage As String = String.Empty If Not ValidateCurrentUrl(errorMessage) Then MessageBox.Show(String.Format("Cannot connect to the SharePoint site: {0}. {1}", CurrentSiteUrl, errorMessage), "SharePoint Connection Error") Return Nothing End If ' Site is valid, so go ahead and get the available field types. Dim siteUri As Uri = New Uri(CurrentSiteUrl, UriKind.Absolute) Dim vsThreadedWaitDialog As IVsThreadedWaitDialog2 = ShowProgressDialog( "Connect to SharePoint", "Connecting to SharePoint site " + CurrentSiteUrl) Dim fieldTypesArray As String() = Me.ProjectService.SharePointConnection.ExecuteCommand(Of Uri, String())( Contoso.SharePoint.Commands.CommandIds.GetFieldTypes, siteUri) If vsThreadedWaitDialog IsNot Nothing Then CloseProgressDialog(vsThreadedWaitDialog) End If Return New ArrayList(fieldTypesArray) End Function ' Returns the default column group names in SharePoint. Friend Function GetFieldGroups() As List(Of String) Dim groups As List(Of String) = New List(Of String)() groups.Add("Base Columns") groups.Add("Core Contact and Calendar Columns") groups.Add("Core Document Columns") groups.Add("Core Task and Issue Columns") groups.Add("Extended Columns") Return groups End Function #End Region #Region "Properties shared by the wizard implementation and the wizard UI" Friend ReadOnly Property ProjectService As ISharePointProjectService Get If projectServiceValue Is Nothing Then projectServiceValue = GetProjectService() End If Return projectServiceValue End Get End Property Friend Property IsSecondPagePopulated As Boolean Friend Property IsSandboxed As Boolean Friend Property FieldType As String Friend Property FieldGroup As String Friend Property FieldName As String Friend Property CurrentSiteUrl As String #End Region #Region "Private methods" Private Function GetLocalHostUrl() As String Const HttpScheme As String = "http" Dim builder As UriBuilder = New UriBuilder(HttpScheme, Environment.MachineName.ToLowerInvariant()) Return builder.ToString() End Function Private Function GetProjectService() As ISharePointProjectService Dim serviceProvider As ServiceProvider = New ServiceProvider(CType(dteObject, IOleServiceProvider)) Return CType(serviceProvider.GetService(GetType(ISharePointProjectService)), ISharePointProjectService) End Function Private Function ShowProgressDialog(ByVal caption As String, ByVal message As String) As IVsThreadedWaitDialog2 Dim oleServiceProvider As IOleServiceProvider = CType(dteObject, IOleServiceProvider) Dim dialogFactory As IVsThreadedWaitDialogFactory = CType(New ServiceProvider(oleServiceProvider).GetService( GetType(SVsThreadedWaitDialogFactory)), IVsThreadedWaitDialogFactory) If dialogFactory Is Nothing Then Throw New InvalidOperationException("The IVsThreadedWaitDialogFactory object could not be retrieved.") End If Dim vsThreadedWaitDialog As IVsThreadedWaitDialog2 = Nothing ErrorHandler.ThrowOnFailure(dialogFactory.CreateInstance(vsThreadedWaitDialog)) ErrorHandler.ThrowOnFailure(vsThreadedWaitDialog.StartWaitDialog(caption, message, Nothing, Nothing, String.Empty, 0, False, True)) Return vsThreadedWaitDialog End Function Private Sub CloseProgressDialog(ByVal vsThreadedWaitDialog As IVsThreadedWaitDialog2) If vsThreadedWaitDialog Is Nothing Then Throw New ArgumentNullException("vsThreadedWaitDialog") End If Dim canceled As Integer ErrorHandler.ThrowOnFailure(vsThreadedWaitDialog.EndWaitDialog(canceled)) End Sub #End Region End Class
using System; using System.Collections; using System.Collections.Generic; using System.Windows; using EnvDTE; using Microsoft.VisualStudio.SharePoint; using Microsoft.VisualStudio; using Microsoft.VisualStudio.Shell; using Microsoft.VisualStudio.Shell.Interop; using IOleServiceProvider = Microsoft.VisualStudio.OLE.Interop.IServiceProvider; namespace ProjectTemplateWizard { internal class SiteColumnWizardModel { private DTE dteObject; private ISharePointProjectService projectServiceValue; private List<string> validatedUrls = new List<string>(); internal SiteColumnWizardModel(DTE dteObject, bool requiresFarmPriveleges) { this.dteObject = dteObject; // Initialize default values for wizard choices. IsSandboxed = !requiresFarmPriveleges; IsSecondPagePopulated = false; FieldType = "Text"; FieldGroup = "Custom Columns"; FieldName = "My Custom Column"; CurrentSiteUrl = GetLocalHostUrl(); } #region Helper methods used by the wizard UI // Specifies whether the current site URL is valid. Uses the ValidateSite SharePoint command to do this. internal bool ValidateCurrentUrl(out string errorMessage) { bool isValid = false; errorMessage = String.Empty; if (validatedUrls.Contains(CurrentSiteUrl)) { isValid = true; } else { Uri uriToValidate = new Uri(CurrentSiteUrl, UriKind.Absolute); IVsThreadedWaitDialog2 vsThreadedWaitDialog = null; try { vsThreadedWaitDialog = ShowProgressDialog("Connect to SharePoint", "Connecting to SharePoint site " + CurrentSiteUrl); isValid = this.ProjectService.SharePointConnection.ExecuteCommand<Uri, bool>( Contoso.SharePoint.Commands.CommandIds.ValidateSite, uriToValidate); } catch (Exception ex) { errorMessage = "An error occurred while validating the site. " + ex.Message; } finally { if (isValid) { validatedUrls.Add(CurrentSiteUrl); } if (vsThreadedWaitDialog != null) { CloseProgressDialog(vsThreadedWaitDialog); } } } return isValid; } // Gets the available field types from the SharePoint site. Uses the GetFieldTypes SharePoint command to do this. internal ArrayList GetFieldTypes() { // If we have not yet validated this site, do it now. string errorMessage; if (!ValidateCurrentUrl(out errorMessage)) { MessageBox.Show(String.Format("Cannot connect to the SharePoint site: {0}. {1}", CurrentSiteUrl, errorMessage), "SharePoint Connection Error"); return null; } // Site is valid, so go ahead and get the available field types. Uri siteUri = new Uri(CurrentSiteUrl, UriKind.Absolute); IVsThreadedWaitDialog2 vsThreadedWaitDialog = ShowProgressDialog( "Connect to SharePoint", "Connecting to SharePoint site " + CurrentSiteUrl); string[] fieldTypesArray = this.ProjectService.SharePointConnection.ExecuteCommand<Uri, string[]>( Contoso.SharePoint.Commands.CommandIds.GetFieldTypes, siteUri); if (vsThreadedWaitDialog != null) { CloseProgressDialog(vsThreadedWaitDialog); } return new ArrayList(fieldTypesArray); } // Returns the default column group names in SharePoint. internal List<string> GetFieldGroups() { List<string> groups = new List<string>(); groups.Add("Base Columns"); groups.Add("Core Contact and Calendar Columns"); groups.Add("Core Document Columns"); groups.Add("Core Task and Issue Columns"); groups.Add("Extended Columns"); return groups; } #endregion #region Properties shared by the wizard implementation and the wizard UI internal ISharePointProjectService ProjectService { get { if (projectServiceValue == null) { projectServiceValue = GetProjectService(); } return projectServiceValue; } } internal bool IsSecondPagePopulated { get; set; } internal bool IsSandboxed { get; set; } internal string FieldType { get; set; } internal string FieldGroup { get; set; } internal string FieldName { get; set; } internal string CurrentSiteUrl { get; set; } #endregion #region Private methods private string GetLocalHostUrl() { const string HttpScheme = "http"; UriBuilder builder = new UriBuilder(HttpScheme, Environment.MachineName.ToLowerInvariant()); return builder.ToString(); } private ISharePointProjectService GetProjectService() { ServiceProvider serviceProvider = new ServiceProvider(dteObject as IOleServiceProvider); return serviceProvider.GetService(typeof(ISharePointProjectService)) as ISharePointProjectService; } private IVsThreadedWaitDialog2 ShowProgressDialog(string caption, string message) { IOleServiceProvider oleServiceProvider = dteObject as IOleServiceProvider; IVsThreadedWaitDialogFactory dialogFactory = new ServiceProvider(oleServiceProvider).GetService( typeof(SVsThreadedWaitDialogFactory)) as IVsThreadedWaitDialogFactory; if (dialogFactory == null) { throw new InvalidOperationException("The IVsThreadedWaitDialogFactory object could not be retrieved."); } IVsThreadedWaitDialog2 vsThreadedWaitDialog = null; ErrorHandler.ThrowOnFailure(dialogFactory.CreateInstance(out vsThreadedWaitDialog)); ErrorHandler.ThrowOnFailure(vsThreadedWaitDialog.StartWaitDialog(caption, message, null, null, String.Empty, 0, false, true)); return vsThreadedWaitDialog; } private void CloseProgressDialog(IVsThreadedWaitDialog2 vsThreadedWaitDialog) { if (vsThreadedWaitDialog == null) { throw new ArgumentNullException("vsThreadedWaitDialog"); } int canceled; ErrorHandler.ThrowOnFailure(vsThreadedWaitDialog.EndWaitDialog(out canceled)); } #endregion } }
프로젝트 서명 관리자를 만들려면
ProjectSigningManager 코드 파일을 연 다음이 파일의 전체 내용을 다음 코드로 대체 합니다.
Imports EnvDTE Imports System Imports System.IO Imports System.Runtime.InteropServices Friend Class ProjectSigningManager Private Const KEY_FILENAME As String = "key.snk" Private keyBuffer As Byte() Private strongNameGenerated As Boolean = False #Region "Methods used by the project wizard" Friend Sub GenerateKeyFile() If Not strongNameGenerated Then keyBuffer = CreateNewKeyPair() strongNameGenerated = True End If End Sub Friend Sub AddKeyFile(ByVal project As Project) If strongNameGenerated Then AddKeyFileToProject(project) End If End Sub #End Region #Region "Private members" Private Function CreateNewKeyPair() As Byte() Dim buffer As IntPtr = IntPtr.Zero Dim bufferSize As UInteger Dim keyBuffer As Byte() Try If 0 = NativeMethods.StrongNameKeyGen(IntPtr.Zero, 0, buffer, bufferSize) Then Marshal.ThrowExceptionForHR(NativeMethods.StrongNameErrorInfo()) End If If buffer = IntPtr.Zero Then Throw New InvalidOperationException("Cannot generate the strong name key.") End If ' Copy generated key to managed memory. keyBuffer = New Byte(bufferSize) {} Marshal.Copy(buffer, keyBuffer, 0, CInt(bufferSize)) Finally ' Free native resources. NativeMethods.StrongNameFreeBuffer(buffer) End Try Return keyBuffer End Function Private Sub AddKeyFileToProject(ByVal project As Project) ' Save the key to a file. If keyBuffer IsNot Nothing Then Try Dim destinationDirectory As String = Path.GetDirectoryName(project.FullName) Dim keySavePath As String = Path.Combine(destinationDirectory, KEY_FILENAME) File.WriteAllBytes(keySavePath, keyBuffer) project.ProjectItems.AddFromFile(keySavePath) ' Add properties in the project to use the key for signing. Dim projProps As EnvDTE.Properties = project.Properties projProps.Item("SignAssembly").Value = True projProps.Item("AssemblyOriginatorKeyFile").Value = KEY_FILENAME Catch e As Exception Throw New Exception("Cannot add the strong name key to the project. " & e.Message, e) End Try End If End Sub Private Class NativeMethods <DllImport("mscoree.dll")> Friend Shared Function StrongNameFreeBuffer(ByVal pbMemory As IntPtr) As Integer End Function <DllImport("mscoree.dll", CharSet:=CharSet.Unicode, ExactSpelling:=True)> Friend Shared Function StrongNameKeyGen(ByVal wszKeyContainer As IntPtr, ByVal dwFlags As UInteger, _ ByRef KeyBlob As IntPtr, ByRef KeyBlobSize As UInteger) As Integer End Function <DllImport("mscoree.dll", CharSet:=CharSet.Unicode)> Friend Shared Function StrongNameErrorInfo() As Integer End Function End Class #End Region End Class
using EnvDTE; using System; using System.IO; using System.Runtime.InteropServices; namespace ProjectTemplateWizard { internal class ProjectSigningManager { private const string KEY_FILENAME = "key.snk"; private byte[] keyBuffer; private bool strongNameGenerated = false; #region Methods used by the project wizard internal void GenerateKeyFile() { if (!strongNameGenerated) { keyBuffer = CreateNewKeyPair(); strongNameGenerated = true; } } internal void AddKeyFile(Project project) { if (strongNameGenerated) { AddKeyFileToProject(project); } } #endregion #region Private members private byte[] CreateNewKeyPair() { IntPtr buffer = IntPtr.Zero; uint bufferSize; byte[] keyBuffer; try { if (0 == NativeMethods.StrongNameKeyGen(IntPtr.Zero, 0, out buffer, out bufferSize)) { Marshal.ThrowExceptionForHR(NativeMethods.StrongNameErrorInfo()); } if (buffer == IntPtr.Zero) { throw new InvalidOperationException("Cannot generate the strong name key."); } // Copy generated key to managed memory. keyBuffer = new byte[bufferSize]; Marshal.Copy(buffer, keyBuffer, 0, (int)bufferSize); } finally { // Free native resources. NativeMethods.StrongNameFreeBuffer(buffer); } return keyBuffer; } private void AddKeyFileToProject(Project project) { // Save the key to a file. if (keyBuffer != null) { try { string destinationDirectory = Path.GetDirectoryName(project.FullName); string keySavePath = Path.Combine(destinationDirectory, KEY_FILENAME); File.WriteAllBytes(keySavePath, keyBuffer); project.ProjectItems.AddFromFile(keySavePath); // Add properties in the project to use the key for signing. EnvDTE.Properties projProps = project.Properties; projProps.Item("SignAssembly").Value = true; projProps.Item("AssemblyOriginatorKeyFile").Value = KEY_FILENAME; } catch (Exception e) { throw new Exception("Cannot add the strong name key to the project. " + e.Message, e); } } } private static class NativeMethods { [DllImport("mscoree.dll")] internal extern static int StrongNameFreeBuffer(IntPtr pbMemory); [DllImport("mscoree.dll", CharSet = CharSet.Unicode, ExactSpelling = true)] internal static extern int StrongNameKeyGen(IntPtr wszKeyContainer, uint dwFlags, out IntPtr KeyBlob, out uint KeyBlobSize); [DllImport("mscoree.dll", CharSet = CharSet.Unicode)] internal static extern int StrongNameErrorInfo(); } #endregion } }
마법사 UI 만들기
마법사 창의 UI 및 마법사 페이지에 UI를 제공하는 두 가지 사용자 정의 컨트롤을 정의하는 XAML을 추가하고 창과 사용자 정의 컨트롤의 동작을 정의하는 코드를 추가합니다.만드는 마법사는 Visual Studio의 SharePoint 프로젝트에 대한 기본 제공 마법사와 유사합니다.
[!참고]
다음 단계에서는 XAML 또는 코드를 프로젝트에 추가한 후 프로젝트에서 컴파일 오류가 발생합니다.이러한 오류는 이후 단계에서 코드를 추가하면 사라집니다.
마법사 창 UI를 만들려면
ProjectTemplateWizard 프로젝트의 WizardWindow.xaml 파일에 대 한 바로 가기 메뉴를 열고 선택 열기 디자이너에서를 클릭 합니다.
디자이너의 XAML 뷰에서 현재 XAML을 다음 XAML로 바꿉니다.이 XAML에서는 제목, 마법사 페이지가 포함된 Grid 및 창 아래쪽의 탐색 단추가 포함된 UI를 정의합니다.
<ui:DialogWindow x:Class="ProjectTemplateWizard.WizardWindow" xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:ui="clr-namespace:Microsoft.VisualStudio.PlatformUI;assembly=Microsoft.VisualStudio.Shell.11.0" xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml" Title="SharePoint Customization Wizard" Height="500" Width="700" ResizeMode="NoResize" Loaded="Window_Loaded" TextOptions.TextFormattingMode="Display"> <Grid> <Grid.RowDefinitions> <RowDefinition Height="75*" /> <RowDefinition Height="364*" /> <RowDefinition Height="1*" /> <RowDefinition Height="60*" /> </Grid.RowDefinitions> <Grid Grid.Row="0" Name="headingGrid" Background="White"> <Label Height="28" HorizontalAlignment="Left" VerticalAlignment="Center" Margin="18,0,0,0" Name="headingLabel" FontWeight="ExtraBold" /> </Grid> <Grid Grid.Row="1" Name="pageGrid" /> <Rectangle Grid.Row="2" Name="separatorRectangle" Fill="White" /> <StackPanel Grid.Row="3" Name="navigationPanel" Orientation="Horizontal"> <Button Content="< _Previous" Margin="300,0,0,0" Height="25" Name="previousButton" Width="85" IsEnabled="False" Click="previousButton_Click" /> <Button Content="_Next >" Margin="10,0,0,0" Height="25" Name="nextButton" Width="85" Click="nextButton_Click" IsDefault="True" /> <Button Content="_Finish" Margin="10,0,0,0" Height="25" Name="finishButton" Width="85" Click="finishButton_Click" /> <Button Content="Cancel" Margin="10,0,0,0" Height="25" Name="cancelButton" Width="85" IsCancel="True" /> </StackPanel> </Grid> </ui:DialogWindow>
[!참고]
이 XAML에서 생성 되는 창에서 파생 되는 DialogWindow 기본 클래스입니다.사용자 지정 WPF 대화 상자 Visual Studio 추가 하면 대화 상자는 다른 Visual Studio 대화 상자와 일관성 있는 스타일 하 고 발생할 수 있는 모달 대화 상자 문제를 방지 하려면이 클래스에서 파생 하는 것이 좋습니다.자세한 내용은 방법: 작성 하 고 대화 상자를 관리 합니다.을 참조하십시오.
Visual Basic 프로젝트를 개발 하는 경우 제거는 ProjectTemplateWizard 네임 스페이스에서의 WizardWindow 클래스 이름에는 x:Class 특성은 Window 요소.이 요소에는 XAML의 첫 번째 줄에 있습니다.완료 되 면 첫 번째 줄은 다음 예제와 같아야 합니다.
<Window x:Class="WizardWindow"
WizardWindow.xaml 파일의 코드 숨김 파일을 엽니다.
제외 하 고는이 파일의 내용을 대체 된 using 선언 다음 코드를 파일 맨 위에 있는.
Public Class WizardWindow Private firstPage As Page1 Private secondPage As Page2 Private Const firstPageLabel As String = "Specify the site and security level for debugging" Private Const secondPageLabel As String = "Configure the site column" Friend Sub New(ByVal presentationModel As SiteColumnWizardModel) InitializeComponent() Me.PresentationModel = presentationModel firstPage = New Page1(Me) secondPage = New Page2(Me) secondPage.Visibility = Visibility.Hidden End Sub Friend Property PresentationModel As SiteColumnWizardModel Private Sub Window_Loaded(ByVal sender As Object, ByVal e As RoutedEventArgs) headingLabel.Content = firstPageLabel pageGrid.Children.Add(firstPage) pageGrid.Children.Add(secondPage) End Sub Private Sub nextButton_Click(ByVal sender As Object, ByVal e As RoutedEventArgs) ' Initialize the second wizard page if this is the first time ' it has been shown with the current site URL. If Not PresentationModel.IsSecondPagePopulated Then If Not ValidateUrl() Then Return End If ' Refresh the UI in the second page. secondPage.ClearControls() secondPage.PopulateSiteColumnOptions() ' Do not do this work again until the user changes the site URL. PresentationModel.IsSecondPagePopulated = True End If ' Display the second wizard page and update related controls. firstPage.Visibility = Visibility.Hidden secondPage.Visibility = Visibility.Visible previousButton.IsEnabled = True nextButton.IsEnabled = False nextButton.IsDefault = False finishButton.IsDefault = True headingLabel.Content = secondPageLabel End Sub ' Display the first wizard page again and update related controls. Private Sub previousButton_Click(ByVal sender As Object, ByVal e As RoutedEventArgs) secondPage.Visibility = Visibility.Hidden firstPage.Visibility = Visibility.Visible previousButton.IsEnabled = False finishButton.IsDefault = False nextButton.IsEnabled = True nextButton.IsDefault = True headingLabel.Content = firstPageLabel End Sub Private Sub finishButton_Click(ByVal sender As Object, ByVal e As RoutedEventArgs) If ValidateUrl() Then DialogResult = True Close() End If End Sub Private Function ValidateUrl() As Boolean Dim errorMessage As String = String.Empty If Not PresentationModel.ValidateCurrentUrl(errorMessage) Then MessageBox.Show(String.Format("Cannot connect to the SharePoint site: {0}. {1}", PresentationModel.CurrentSiteUrl, errorMessage), "SharePoint Connection Error") Return False End If Return True End Function End Class
using System; using System.Windows; using Microsoft.VisualStudio.PlatformUI; namespace ProjectTemplateWizard { public partial class WizardWindow : DialogWindow { private Page1 firstPage; private Page2 secondPage; private const string firstPageLabel = "Specify the site and security level for debugging"; private const string secondPageLabel = "Configure the site column"; internal WizardWindow(SiteColumnWizardModel presentationModel) { InitializeComponent(); this.PresentationModel = presentationModel; firstPage = new Page1(this); secondPage = new Page2(this); secondPage.Visibility = Visibility.Hidden; } internal SiteColumnWizardModel PresentationModel { get; set; } private void Window_Loaded(object sender, RoutedEventArgs e) { headingLabel.Content = firstPageLabel; pageGrid.Children.Add(firstPage); pageGrid.Children.Add(secondPage); } private void nextButton_Click(object sender, RoutedEventArgs e) { // Initialize the second wizard page if this is the first time // it has been shown with the current site URL. if (!PresentationModel.IsSecondPagePopulated) { if (!ValidateUrl()) { return; } // Refresh the UI in the second page. secondPage.ClearControls(); secondPage.PopulateSiteColumnOptions(); // Do not do this work again until the user changes the site URL. PresentationModel.IsSecondPagePopulated = true; } // Display the second wizard page and update related controls. firstPage.Visibility = Visibility.Hidden; secondPage.Visibility = Visibility.Visible; previousButton.IsEnabled = true; nextButton.IsEnabled = false; finishButton.IsDefault = true; headingLabel.Content = secondPageLabel; } // Display the first wizard page again and update related controls. private void previousButton_Click(object sender, RoutedEventArgs e) { secondPage.Visibility = Visibility.Hidden; firstPage.Visibility = Visibility.Visible; previousButton.IsEnabled = false; finishButton.IsDefault = false; nextButton.IsEnabled = true; nextButton.IsDefault = true; headingLabel.Content = firstPageLabel; } private void finishButton_Click(object sender, RoutedEventArgs e) { if (ValidateUrl()) { DialogResult = true; Close(); } } private bool ValidateUrl() { string errorMessage; if (!PresentationModel.ValidateCurrentUrl(out errorMessage)) { MessageBox.Show(String.Format("Cannot connect to the SharePoint site: {0}. {1}", PresentationModel.CurrentSiteUrl, errorMessage), "SharePoint Connection Error"); return false; } return true; } } }
첫 번째 마법사 페이지 UI를 만들려면
ProjectTemplateWizard 프로젝트 Page1.xaml 파일의 바로 가기 메뉴를 열고 선택 열기 사용자 정의 컨트롤 디자이너에서 엽니다.
디자이너의 XAML 뷰에서 현재 XAML을 다음 XAML로 바꿉니다.XAML 디버깅에 사용할 로컬 사이트의 URL을 사용자가 입력할 수 있는 텍스트 상자를 포함 하는 UI를 정의 합니다.UI 프로젝트가 샌드박스가 적용 된 지 여부를 사용자 지정할 수 있습니다 옵션 단추가 포함 됩니다.
<UserControl x:Class="ProjectTemplateWizard.Page1" xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml" xmlns:mc="https://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:d="https://schemas.microsoft.com/expression/blend/2008" mc:Ignorable="d" d:DesignHeight="364" d:DesignWidth="700" Loaded="UserControl_Loaded"> <Grid Height="364" HorizontalAlignment="Left" Name="page1Grid" Width="700"> <Grid.ColumnDefinitions> <ColumnDefinition Width="20*" /> <ColumnDefinition Width="548*" /> <ColumnDefinition Width="132*" /> </Grid.ColumnDefinitions> <Grid.RowDefinitions> <RowDefinition Height="Auto" /> <RowDefinition Height="Auto" /> <RowDefinition Height="Auto" /> <RowDefinition Height="Auto" /> </Grid.RowDefinitions> <TextBox Grid.Row="1" Grid.Column="1" Margin="5,0,1,0" Height="23" Name="siteUrlTextBox" TextChanged="siteUrlTextBox_TextChanged" /> <Label Grid.Row="0" Grid.Column="1" Margin="0,20,0,0" Name="siteLabel" FontWeight="Bold" Target="{Binding ElementName=siteUrlTextBox}" Content="What local _site do you want to use for debugging?" /> <Button Grid.Row="1" Grid.Column="2" Content="_Validate" Height="25" Name="validateButton" Width="88" Click="validateButton_Click" HorizontalAlignment="Left" Margin="5,0,0,0" VerticalAlignment="Top" /> <Label Grid.Row="2" Grid.Column="1" Margin="0,10,0,0" Content="What is the trust level for this SharePoint solution?" Name="trustLabel" FontWeight="Bold" /> <StackPanel Grid.Row="3" Grid.Column="1" Grid.ColumnSpan="2" Orientation="Vertical"> <RadioButton Content="Deploy as a sand_boxed solution" Margin="5,0,0,0" Name="sandboxedSolutionRadioButton" FontWeight="Bold" Checked="sandboxedSolutionRadioButton_Checked" /> <TextBlock TextWrapping="WrapWithOverflow" Margin="20,7,50,0">Clicking this option causes the solution to be deployed as a Sandboxed solution. Sandboxed solutions can be deployed by the site collection owner and are run in a secure, monitored process that has limited resource access.</TextBlock> <RadioButton Content="Deploy as a _farm solution" Margin="5,7,0,0" Name="farmSolutionRadioButton" FontWeight="Bold" Checked="farmSolutionRadioButton_Checked" /> <TextBlock TextWrapping="WrapWithOverflow" Margin="20,7,50,0">Clicking this option means that users must have SharePoint administrator privileges to run or deploy the solution.</TextBlock> </StackPanel> </Grid> </UserControl>
Visual Basic 프로젝트를 개발하는 중이면 UserControl 요소의 x:Class 특성에 있는 Page1 클래스 이름에서 ProjectTemplateWizard 네임스페이스를 제거합니다.이 네임스페이스는 XAML의 첫 번째 줄에 있습니다.지금까지 작업을 마친 후의 첫 번째 줄은 다음과 같습니다.
<UserControl x:Class="Page1"
Page1.xaml 파일의 내용을 제외 하 고 대체 된 using 선언 다음 코드를 파일 맨 위에 있는.
Public Class Page1 Private mainWindow As WizardWindow Friend Sub New(ByVal mainWindow As WizardWindow) Me.mainWindow = mainWindow InitializeComponent() End Sub Private Sub UserControl_Loaded(ByVal sender As Object, ByVal e As RoutedEventArgs) If (mainWindow.PresentationModel.IsSandboxed) Then sandboxedSolutionRadioButton.IsChecked = True Else sandboxedSolutionRadioButton.IsEnabled = False farmSolutionRadioButton.IsChecked = True End If siteUrlTextBox.Text = mainWindow.PresentationModel.CurrentSiteUrl End Sub ' Validate that the URL exists on the development computer. Private Sub validateButton_Click(ByVal sender As Object, ByVal e As RoutedEventArgs) Dim errorMessage As String = String.Empty validateButton.IsEnabled = False If Not mainWindow.PresentationModel.ValidateCurrentUrl(errorMessage) Then MessageBox.Show(String.Format("Cannot connect to the SharePoint site: {0}. {1}", mainWindow.PresentationModel.CurrentSiteUrl, errorMessage), "SharePoint Connection Error") Else MessageBox.Show("Successfully connected to SharePoint site " + mainWindow.PresentationModel.CurrentSiteUrl, "Connection Successful") End If validateButton.IsEnabled = True End Sub ' Prevent users from finishing the wizard if the URL is not formatted correctly. Private Sub siteUrlTextBox_TextChanged(ByVal sender As Object, ByVal e As TextChangedEventArgs) Dim url As String = EnsureTrailingSlash(siteUrlTextBox.Text) ' Perform some basic error-checking on the URL here. If url.Length > 0 AndAlso Uri.IsWellFormedUriString(Uri.EscapeUriString(url), UriKind.Absolute) Then mainWindow.finishButton.IsEnabled = True mainWindow.nextButton.IsEnabled = True validateButton.IsEnabled = True mainWindow.PresentationModel.CurrentSiteUrl = url mainWindow.PresentationModel.IsSecondPagePopulated = False Else mainWindow.finishButton.IsEnabled = False mainWindow.nextButton.IsEnabled = False validateButton.IsEnabled = False End If End Sub Private Sub sandboxedSolutionRadioButton_Checked(ByVal sender As Object, ByVal e As RoutedEventArgs) mainWindow.PresentationModel.IsSandboxed = CBool(sandboxedSolutionRadioButton.IsChecked) End Sub Private Sub farmSolutionRadioButton_Checked(ByVal sender As Object, ByVal e As RoutedEventArgs) mainWindow.PresentationModel.IsSandboxed = CBool(sandboxedSolutionRadioButton.IsChecked) End Sub Private Function EnsureTrailingSlash(ByVal url As String) If Not String.IsNullOrEmpty(url) AndAlso url(url.Length - 1) <> "/" Then url += "/" End If Return url End Function End Class
using System; using System.Windows; using System.Windows.Controls; namespace ProjectTemplateWizard { public partial class Page1 : UserControl { private WizardWindow mainWindow; internal Page1(WizardWindow mainWindow) { this.mainWindow = mainWindow; InitializeComponent(); } private void UserControl_Loaded(object sender, RoutedEventArgs e) { if (mainWindow.PresentationModel.IsSandboxed) { sandboxedSolutionRadioButton.IsChecked = true; } else { sandboxedSolutionRadioButton.IsEnabled = false; farmSolutionRadioButton.IsChecked = true; } siteUrlTextBox.Text = mainWindow.PresentationModel.CurrentSiteUrl; } // Validate that the URL exists on the development computer. private void validateButton_Click(object sender, RoutedEventArgs e) { string errorMessage; validateButton.IsEnabled = false; if (!mainWindow.PresentationModel.ValidateCurrentUrl(out errorMessage)) { MessageBox.Show(String.Format("Cannot connect to the SharePoint site: {0}. {1}", mainWindow.PresentationModel.CurrentSiteUrl, errorMessage), "SharePoint Connection Error"); } else { MessageBox.Show("Successfully connected to SharePoint site " + mainWindow.PresentationModel.CurrentSiteUrl, "Connection Successful"); } validateButton.IsEnabled = true; } // Prevent users from finishing the wizard if the URL is not formatted correctly. private void siteUrlTextBox_TextChanged(object sender, TextChangedEventArgs e) { string url = EnsureTrailingSlash(siteUrlTextBox.Text); // Perform some basic error-checking on the URL here. if ((url.Length > 0) && (Uri.IsWellFormedUriString(Uri.EscapeUriString(url), UriKind.Absolute))) { mainWindow.finishButton.IsEnabled = true; mainWindow.nextButton.IsEnabled = true; validateButton.IsEnabled = true; mainWindow.PresentationModel.CurrentSiteUrl = url; mainWindow.PresentationModel.IsSecondPagePopulated = false; } else { mainWindow.finishButton.IsEnabled = false; mainWindow.nextButton.IsEnabled = false; validateButton.IsEnabled = false; } } private void sandboxedSolutionRadioButton_Checked(object sender, RoutedEventArgs e) { mainWindow.PresentationModel.IsSandboxed = (bool)sandboxedSolutionRadioButton.IsChecked; } private void farmSolutionRadioButton_Checked(object sender, RoutedEventArgs e) { mainWindow.PresentationModel.IsSandboxed = (bool)sandboxedSolutionRadioButton.IsChecked; } private string EnsureTrailingSlash(string url) { if (!String.IsNullOrEmpty(url) && url[url.Length - 1] != '/') { url += '/'; } return url; } } }
두 번째 마법사 페이지 UI를 만들려면
ProjectTemplateWizard 프로젝트 Page2.xaml 파일의 바로 가기 메뉴를 열고 선택 열기.
사용자 정의 컨트롤이 디자이너에서 열립니다.
XAML 뷰에서 현재 XAML을 다음 XAML로 바꿉니다.이 XAML에서는 사이트 열의 기본 형식을 선택하기 위한 드롭다운 목록, 갤러리에 사이트 열을 표시할 기본 제공 그룹 또는 사용자 지정 그룹을 지정하기 위한 콤보 상자 및 사이트 열의 이름을 지정하기 위한 텍스트 상자가 포함된 UI를 정의합니다.
<UserControl x:Class="ProjectTemplateWizard.Page2" xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml" xmlns:mc="https://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:d="https://schemas.microsoft.com/expression/blend/2008" mc:Ignorable="d" d:DesignHeight="364" d:DesignWidth="700" Loaded="UserControl_Loaded"> <Grid Height="364" HorizontalAlignment="Left" Name="page2Grid" Width="700"> <Grid.ColumnDefinitions> <ColumnDefinition Width="20*" /> <ColumnDefinition Width="Auto" /> <ColumnDefinition Width="450*" /> </Grid.ColumnDefinitions> <Grid.RowDefinitions> <RowDefinition Height="Auto" /> <RowDefinition Height="Auto" /> <RowDefinition Height="Auto" /> </Grid.RowDefinitions> <Label Grid.Row="0" Grid.Column="1" Margin="0,20,0,0" Content="_Type:" Name="fieldTypeLabel" FontWeight="Bold" Target="{Binding ElementName=fieldTypeComboBox}"/> <Label Grid.Row="1" Grid.Column="1" Margin="0,10,0,0" Content="_Group:" Name="groupLabel" FontWeight="Bold" Target="{Binding ElementName=groupComboBox}"/> <Label Grid.Row="2" Grid.Column="1" Margin="0,10,0,0" Content="_Name:" Name="nameLabel" FontWeight="Bold" Target="{Binding ElementName=nameTextBox}"/> <ComboBox Grid.Row="0" Grid.Column="2" HorizontalAlignment="Left" Margin="0,20,0,0" Height="23" Name="fieldTypeComboBox" Width="450" SelectionChanged="fieldTypeComboBox_SelectionChanged" /> <ComboBox Grid.Row="1" Grid.Column="2" HorizontalAlignment="Left" Margin="0,10,0,0" Height="23" Name="groupComboBox" Width="450" IsEditable="True" /> <TextBox Grid.Row="2" Grid.Column="2" HorizontalAlignment="Left" Margin="0,10,0,0" Height="23" Name="nameTextBox" Width="450" TextChanged="nameTextBox_TextChanged" /> </Grid> </UserControl>
Visual Basic 프로젝트를 개발하는 중이면 UserControl 요소의 x:Class 특성에 있는 Page2 클래스 이름에서 ProjectTemplateWizard 네임스페이스를 제거합니다.이 네임스페이스는 XAML의 첫 번째 줄에 있습니다.지금까지 작업을 마친 후의 첫 번째 줄은 다음과 같습니다.
<UserControl x:Class="Page2"
Page2.xaml 파일의 코드 숨김 파일의 내용을 제외 하 고 대체 된 using 선언 다음 코드를 파일 맨 위에 있는.
Public Class Page2 Private mainWindow As WizardWindow Private innerTextBoxForGroupComboBox As TextBox Friend Sub New(ByVal mainWindow As WizardWindow) Me.mainWindow = mainWindow InitializeComponent() End Sub Friend Sub ClearControls() fieldTypeComboBox.Items.Clear() groupComboBox.Items.Clear() nameTextBox.Clear() End Sub Friend Sub PopulateSiteColumnOptions() ' Add the available field type names to the combo box. Dim fieldTypes As System.Collections.ArrayList = mainWindow.PresentationModel.GetFieldTypes() If fieldTypes IsNot Nothing Then fieldTypes.Sort() For Each fieldValue As String In fieldTypes fieldTypeComboBox.Items.Add(fieldValue) Next fieldTypeComboBox.SelectedIndex = 0 End If ' Add the default group names to the combo box. Dim fieldGroups As List(Of String) = mainWindow.PresentationModel.GetFieldGroups() For Each fieldGroupValue As String In fieldGroups groupComboBox.Items.Add(fieldGroupValue) Next groupComboBox.SelectedIndex = 0 End Sub Private Sub UserControl_Loaded(ByVal sender As Object, ByVal e As RoutedEventArgs) ' Handle the TextChanged event of the underlying TextBox for the ComboBox. This enables us to determine ' 1) when the user selects an item in the list and 2) when they type their own custom group name. ' The ComboBox.SelectionChanged event is not raised when you type in an editable ComboboBox. innerTextBoxForGroupComboBox = CType(groupComboBox.Template.FindName( "PART_EditableTextBox", groupComboBox), TextBox) AddHandler innerTextBoxForGroupComboBox.TextChanged, AddressOf innerTextBoxForGroupComboBox_TextChanged End Sub Private Sub fieldTypeComboBox_SelectionChanged(ByVal sender As Object, ByVal e As SelectionChangedEventArgs) mainWindow.PresentationModel.FieldType = CStr(fieldTypeComboBox.SelectedItem) End Sub Private Sub innerTextBoxForGroupComboBox_TextChanged(ByVal sender As Object, ByVal e As TextChangedEventArgs) mainWindow.PresentationModel.FieldGroup = groupComboBox.Text End Sub Private Sub nameTextBox_TextChanged(ByVal sender As Object, ByVal e As TextChangedEventArgs) mainWindow.PresentationModel.FieldName = nameTextBox.Text End Sub End Class
using System.Windows; using System.Windows.Controls; namespace ProjectTemplateWizard { public partial class Page2 : UserControl { private WizardWindow mainWindow; private TextBox innerTextBoxForGroupComboBox; internal Page2(WizardWindow mainWindow) { this.mainWindow = mainWindow; InitializeComponent(); } internal void ClearControls() { fieldTypeComboBox.Items.Clear(); groupComboBox.Items.Clear(); nameTextBox.Clear(); } internal void PopulateSiteColumnOptions() { // Add the available field type names to the combo box. System.Collections.ArrayList fieldTypes = mainWindow.PresentationModel.GetFieldTypes(); if (fieldTypes != null) { fieldTypes.Sort(); foreach (string fieldValue in fieldTypes) { fieldTypeComboBox.Items.Add(fieldValue); } fieldTypeComboBox.SelectedIndex = 0; } // Add the default group names to the combo box. System.Collections.Generic.List<string> fieldGroups = mainWindow.PresentationModel.GetFieldGroups(); foreach (string fieldGroupValue in fieldGroups) { groupComboBox.Items.Add(fieldGroupValue); } groupComboBox.SelectedIndex = 0; } private void UserControl_Loaded(object sender, RoutedEventArgs e) { // Handle the TextChanged event of the underlying TextBox for the ComboBox. This enables us to determine // 1) when the user selects an item in the list and 2) when they type their own custom group name. // The ComboBox.SelectionChanged event is not raised when you type in an editable ComboboBox. innerTextBoxForGroupComboBox = groupComboBox.Template.FindName( "PART_EditableTextBox", groupComboBox) as TextBox; innerTextBoxForGroupComboBox.TextChanged += innerTextBoxForGroupComboBox_TextChanged; } private void fieldTypeComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e) { mainWindow.PresentationModel.FieldType = (string)fieldTypeComboBox.SelectedItem; } void innerTextBoxForGroupComboBox_TextChanged(object sender, TextChangedEventArgs e) { mainWindow.PresentationModel.FieldGroup = groupComboBox.Text; } private void nameTextBox_TextChanged(object sender, TextChangedEventArgs e) { mainWindow.PresentationModel.FieldName = nameTextBox.Text; } } }
마법사 구현
IWizard 인터페이스를 구현하여 마법사의 기본 기능을 정의합니다.이 인터페이스는 마법사가 시작되고 완료될 때와 마법사 실행 중의 특정한 때에 Visual Studio에서 호출하는 메서드를 정의합니다.
마법사를 구현하려면
ProjectTemplateWizard 프로젝트에서 SiteColumnProjectWizard 코드 파일을 엽니다.
이 파일의 전체 내용을 다음 코드로 바꿉니다.
Imports EnvDTE Imports Microsoft.VisualStudio.SharePoint Imports Microsoft.VisualStudio.TemplateWizard Imports System Imports System.Collections.Generic Public Class SiteColumnProjectWizard Implements IWizard Private wizardUI As WizardWindow Private dteObject As DTE Private presentationModel As SiteColumnWizardModel Private signingManager As ProjectSigningManager Public Sub New() signingManager = New ProjectSigningManager() End Sub Public Sub RunStarted(ByVal automationObject As Object, ByVal replacementsDictionary As Dictionary(Of String, String), _ ByVal runKind As WizardRunKind, ByVal customParams() As Object) Implements IWizard.RunStarted dteObject = CType(automationObject, DTE) presentationModel = New SiteColumnWizardModel(dteObject, False) If Not presentationModel.ProjectService.IsSharePointInstalled Then Dim errorString As String = "A SharePoint server is not installed on this computer. A SharePoint server " & "must be installed to work with SharePoint projects." System.Windows.MessageBox.Show(errorString, "SharePoint Not Installed", System.Windows.MessageBoxButton.OK, System.Windows.MessageBoxImage.Error) Throw New WizardCancelledException(errorString) End If wizardUI = New WizardWindow(presentationModel) Dim dialogCompleted? As Boolean = wizardUI.ShowModal() If (dialogCompleted = True) Then replacementsDictionary.Add("$selectedfieldtype$", presentationModel.FieldType) replacementsDictionary.Add("$selectedgrouptype$", presentationModel.FieldGroup) replacementsDictionary.Add("$fieldname$", presentationModel.FieldName) signingManager.GenerateKeyFile() Else Throw New WizardCancelledException() End If End Sub ' Populate the SiteUrl and IsSandboxedSolution properties in the new project, and add a new ' key.snk file to the project. Public Sub ProjectFinishedGenerating(ByVal project As Project) _ Implements IWizard.ProjectFinishedGenerating Dim sharePointProject As ISharePointProject = presentationModel.ProjectService.Convert(Of Project, ISharePointProject)(project) sharePointProject.SiteUrl = New Uri(presentationModel.CurrentSiteUrl, UriKind.Absolute) sharePointProject.IsSandboxedSolution = presentationModel.IsSandboxed signingManager.AddKeyFile(project) End Sub ' Always return true; this IWizard implementation throws a WizardCancelledException ' that is handled by Visual Studio if the user cancels the wizard. Public Function ShouldAddProjectItem(ByVal filePath As String) As Boolean _ Implements IWizard.ShouldAddProjectItem Return True End Function ' The following IWizard methods are not used in this example. Public Sub BeforeOpeningFile(ByVal projectItem As ProjectItem) _ Implements IWizard.BeforeOpeningFile End Sub Public Sub ProjectItemFinishedGenerating(ByVal projectItem As ProjectItem) _ Implements IWizard.ProjectItemFinishedGenerating End Sub Public Sub RunFinished() Implements IWizard.RunFinished End Sub End Class
using EnvDTE; using Microsoft.VisualStudio.SharePoint; using Microsoft.VisualStudio.TemplateWizard; using System; using System.Collections.Generic; namespace ProjectTemplateWizard { public class SiteColumnProjectWizard : IWizard { private WizardWindow wizardUI; private DTE dteObject; private SiteColumnWizardModel presentationModel; private ProjectSigningManager signingManager; public SiteColumnProjectWizard() { signingManager = new ProjectSigningManager(); } public void RunStarted(object automationObject, Dictionary<string, string> replacementsDictionary, WizardRunKind runKind, object[] customParams) { dteObject = automationObject as DTE; presentationModel = new SiteColumnWizardModel(dteObject, false); if (!presentationModel.ProjectService.IsSharePointInstalled) { string errorString = "A SharePoint server is not installed on this computer. A SharePoint server " + "must be installed to work with SharePoint projects."; System.Windows.MessageBox.Show(errorString, "SharePoint Not Installed", System.Windows.MessageBoxButton.OK, System.Windows.MessageBoxImage.Error); throw new WizardCancelledException(errorString); } wizardUI = new WizardWindow(presentationModel); Nullable<bool> dialogCompleted = wizardUI.ShowModal(); if (dialogCompleted == true) { replacementsDictionary.Add("$selectedfieldtype$", presentationModel.FieldType); replacementsDictionary.Add("$selectedgrouptype$", presentationModel.FieldGroup); replacementsDictionary.Add("$fieldname$", presentationModel.FieldName); signingManager.GenerateKeyFile(); } else { throw new WizardCancelledException(); } } // Populate the SiteUrl and IsSandboxedSolution properties in the new project, and add a new // key.snk file to the project. public void ProjectFinishedGenerating(Project project) { ISharePointProject sharePointProject = presentationModel.ProjectService.Convert<Project, ISharePointProject>(project); sharePointProject.SiteUrl = new Uri(presentationModel.CurrentSiteUrl, UriKind.Absolute); sharePointProject.IsSandboxedSolution = presentationModel.IsSandboxed; signingManager.AddKeyFile(project); } // Always return true; this IWizard implementation throws a WizardCancelledException // that is handled by Visual Studio if the user cancels the wizard. public bool ShouldAddProjectItem(string filePath) { return true; } // The following IWizard methods are not used in this example. public void BeforeOpeningFile(ProjectItem projectItem) { } public void ProjectItemFinishedGenerating(ProjectItem projectItem) { } public void RunFinished() { } } }
SharePoint 명령 만들기
SharePoint 서버 개체 모델을 호출하는 두 개의 사용자 지정 명령을 만듭니다.한 명령은 사용자가 마법사에서 입력하는 사이트 URL이 유효한지 여부를 확인합니다.다른 명령은 사용자가 새 사이트 열의 기반으로 사용할 필드 형식을 선택할 수 있도록 지정된 SharePoint 사이트에서 모든 필드 형식을 가져옵니다.
SharePoint 명령을 정의하려면
SharePointCommands 프로젝트에서 Commands 코드 파일을 엽니다.
이 파일의 전체 내용을 다음 코드로 바꿉니다.
Imports Microsoft.SharePoint Imports Microsoft.VisualStudio.SharePoint.Commands Namespace Contoso.SharePoint.Commands Friend Class Commands <SharePointCommand(CommandIds.ValidateSite)> _ Private Function ValidateSite(ByVal context As ISharePointCommandContext, ByVal url As Uri) As Boolean Using site As SPSite = New SPSite(url.AbsoluteUri) Dim webUrl As String = DetermineWebUrl(url.AbsolutePath, site.ServerRelativeUrl) If webUrl IsNot Nothing Then Using web As SPWeb = site.OpenWeb(webUrl, True) Return web.Exists End Using End If End Using Return False End Function ' For simplicity, this command does not check to make sure the provided Uri is valid. ' Use the ValidateSite command to verify that the Uri is valid first. <SharePointCommand(CommandIds.GetFieldTypes)> _ Private Function GetFieldTypes(ByVal context As ISharePointCommandContext, ByVal url As Uri) As String() Dim columnDefinitions As List(Of String) = New List(Of String)() Using site As SPSite = New SPSite(url.AbsoluteUri) Dim webUrl As String = DetermineWebUrl(url.AbsolutePath, site.ServerRelativeUrl) Using web As SPWeb = site.OpenWeb(webUrl, True) For Each columnDefinition As SPFieldTypeDefinition In web.FieldTypeDefinitionCollection columnDefinitions.Add(columnDefinition.TypeName) Next ' SharePoint commands cannot serialize List<string>, so return an array. Return columnDefinitions.ToArray() End Using End Using End Function Private Function DetermineWebUrl(ByVal serverRelativeInputUrl As String, ByVal serverRelativeSiteUrl As String) As String ' Make sure both URLs have a trailing slash. serverRelativeInputUrl = EnsureTrailingSlash(serverRelativeInputUrl) serverRelativeSiteUrl = EnsureTrailingSlash(serverRelativeSiteUrl) Dim webUrl As String = Nothing Dim isSubString As Boolean = serverRelativeInputUrl.StartsWith(serverRelativeSiteUrl, StringComparison.OrdinalIgnoreCase) If isSubString Then ' The Web URL cannot have escaped characters. webUrl = Uri.UnescapeDataString(serverRelativeInputUrl.Substring(serverRelativeSiteUrl.Length)) End If Return webUrl End Function Private Function EnsureTrailingSlash(ByVal url As String) If Not String.IsNullOrEmpty(url) AndAlso url(url.Length - 1) <> "/" Then url += "/" End If Return url End Function End Class End Namespace
using System; using System.Collections.Generic; using Microsoft.SharePoint; using Microsoft.VisualStudio.SharePoint.Commands; namespace Contoso.SharePoint.Commands { internal class Commands { [SharePointCommand(CommandIds.ValidateSite)] private bool ValidateSite(ISharePointCommandContext context, Uri url) { using (SPSite site = new SPSite(url.AbsoluteUri)) { string webUrl = DetermineWebUrl(url.AbsolutePath, site.ServerRelativeUrl); if (webUrl != null) { using (SPWeb web = site.OpenWeb(webUrl, true)) { return web.Exists; } } } return false; } // For simplicity, this command does not check to make sure the provided Uri is valid. // Use the ValidateSite command to verify that the Uri is valid first. [SharePointCommand(CommandIds.GetFieldTypes)] private string[] GetFieldTypes(ISharePointCommandContext context, Uri url) { List<string> columnDefinitions = new List<string>(); using (SPSite site = new SPSite(url.AbsoluteUri)) { string webUrl = DetermineWebUrl(url.AbsolutePath, site.ServerRelativeUrl); using (SPWeb web = site.OpenWeb(webUrl, true)) { foreach (SPFieldTypeDefinition columnDefinition in web.FieldTypeDefinitionCollection) { columnDefinitions.Add(columnDefinition.TypeName); } // SharePoint commands cannot serialize List<string>, so return an array. return columnDefinitions.ToArray(); } } } private string DetermineWebUrl(string serverRelativeInputUrl, string serverRelativeSiteUrl) { // Make sure both URLs have a trailing slash. serverRelativeInputUrl = EnsureTrailingSlash(serverRelativeInputUrl); serverRelativeSiteUrl = EnsureTrailingSlash(serverRelativeSiteUrl); string webUrl = null; bool isSubString = serverRelativeInputUrl.StartsWith(serverRelativeSiteUrl, StringComparison.OrdinalIgnoreCase); if (isSubString) { // The Web URL cannot have escaped characters. webUrl = Uri.UnescapeDataString(serverRelativeInputUrl.Substring(serverRelativeSiteUrl.Length)); } return webUrl; } private string EnsureTrailingSlash(string url) { if (!String.IsNullOrEmpty(url) && url[url.Length - 1] != '/') { url += '/'; } return url; } } }
검사점
이 연습의 이전 단계를 통해 마법사를 위한 모든 코드가 프로젝트에 포함되었습니다.프로젝트를 빌드하여 오류 없이 컴파일되는지 확인합니다.
프로젝트를 빌드하려면
- 메뉴 표시줄에서 선택 빌드, 솔루션 빌드.
프로젝트 템플릿에서 key.snk 파일 제거
연습: 프로젝트 템플릿을 사용하여 사이트 열 프로젝트 항목 만들기, 1부에서 만든 프로젝트 템플릿에는 각 사이트 열 프로젝트 인스턴스에 서명하는 데 사용되는 key.snk 파일이 포함되어 있습니다.이제 마법사에서 각 프로젝트에 대한 새 key.snk 파일을 생성하기 때문에 이 key.snk 파일은 더 이상 필요하지 않습니다.프로젝트 템플릿에서 key.snk 파일을 제거하고 이 파일에 대한 참조를 제거합니다.
프로젝트 템플릿에서 key.snk 파일을 제거하려면
솔루션 탐색기아래에서 SiteColumnProjectTemplate 노드, 바로 가기 메뉴를 엽니다의 key.snk 파일을 및 다음 선택 삭제.
확인 대화 상자에서 선택 된 확인 단추입니다.
아래는 SiteColumnProjectTemplate 노드를 SiteColumnProjectTemplate.vstemplate 파일을 연 다음 요소를 제거 합니다.
<ProjectItem ReplaceParameters="false" TargetFileName="key.snk">key.snk</ProjectItem>
파일을 저장한 후 닫습니다.
아래는 SiteColumnProjectTemplate 노드를 ProjectTemplate.csproj 또는 ProjectTemplate.vbproj 파일을 열고 다음을 제거 PropertyGroup 요소를.
<PropertyGroup> <SignAssembly>true</SignAssembly> <AssemblyOriginatorKeyFile>key.snk</AssemblyOriginatorKeyFile> </PropertyGroup>
다음 None 요소를 제거합니다.
<None Include="key.snk" />
파일을 저장한 후 닫습니다.
마법사를 프로젝트 템플릿과 연결
마법사를 구현했으므로 이 마법사를 사이트 열 프로젝트 템플릿과 연결해야 합니다.이렇게 하려면 세 가지 절차를 완료해야 합니다.
강력한 이름으로 마법사 어셈블리에 서명합니다.
마법사 어셈블리의 공개 키 토큰을 가져옵니다.
사이트 열 프로젝트 템플릿의 .vstemplate 파일에서 마법사 어셈블리에 대한 참조를 추가합니다.
강력한 이름으로 마법사 어셈블리에 서명하려면
솔루션 탐색기, 바로 가기 메뉴를 열고를 ProjectTemplateWizard 프로젝트를 하 고 선택 속성.
서명 탭에서 어셈블리 서명 확인란을 선택합니다.
에 있는 강력한 이름 키 파일 선택 목록에서 선택 < 새로... >.
에 강력한 이름 키 만들기 대화 상자에서 선택을 취소에서 새 키 파일의 이름을 입력은 암호로 내 키 파일 보호 확인란을 선택한 다음 선택은 확인 단추.
바로 가기 메뉴를 열고는 ProjectTemplateWizard 프로젝트를 하 고 선택 빌드 ProjectTemplateWizard.dll 파일을 만들 수.
마법사 어셈블리의 공개 키 토큰을 가져오려면
에 시작 메뉴, 선택 모든 프로그램, 선택 Microsoft Visual Studio 2012, 선택 Visual Studio 도구, 다음 선택 개발자가 명령 프롬프트에 VS2012.
Visual Studio 명령 프롬프트 창이 열립니다.
다음 명령을 실행 대체 PathToWizardAssembly ProjectTemplateWizard.dll 빌드된 어셈블리 ProjectTemplateWizard 프로젝트 개발 컴퓨터에 대 한 전체 경로:
sn.exe -T PathToWizardAssembly
ProjectTemplateWizard.dll 어셈블리의 공개 키 토큰은 Visual Studio 명령 프롬프트 창에 기록됩니다.
Visual Studio 명령 프롬프트 창을 계속 열어 둡니다.공개 키 토큰은 다음 절차 중에 필요합니다.
마법사 어셈블리에 대한 참조를 .vstemplate 파일에 추가하려면
솔루션 탐색기에서 SiteColumnProjectTemplate 프로젝트 노드를 확장하고 SiteColumnProjectTemplate.vstemplate 파일을 엽니다.
파일의 끝 부분에서 </TemplateContent> 및 </VSTemplate> 태그 사이에 다음 WizardExtension 요소를 추가합니다.PublicKeyToken 특성의 your token 값을 이전 절차에서 가져온 공개 키 토큰으로 바꿉니다.
<WizardExtension> <Assembly>ProjectTemplateWizard, Version=1.0.0.0, Culture=neutral, PublicKeyToken=your token</Assembly> <FullClassName>ProjectTemplateWizard.SiteColumnProjectWizard</FullClassName> </WizardExtension>
WizardExtension 요소에 대한 자세한 내용은 WizardExtension 요소(Visual Studio 템플릿)를 참조하십시오.
파일을 저장한 후 닫습니다.
프로젝트 템플릿의 Elements.xml 파일에 대체 가능한 매개 변수 추가
대체 가능한 매개 변수 여러 개를 SiteColumnProjectTemplate 프로젝트의 Elements.xml 파일에 추가합니다.이러한 매개 변수는 앞에서 정의한 SiteColumnProjectWizard 클래스의 RunStarted 메서드에서 초기화됩니다.사용자가 사이트 열 프로젝트를 만들면 Visual Studio에서는 자동으로 새 프로젝트의 Elements.xml 파일에 있는 이러한 매개 변수를 마법사에서 지정한 값으로 바꿉니다.
대체 가능한 매개 변수는 달러 기호($) 문자로 시작하고 끝나는 토큰입니다.대체 가능한 매개 변수를 직접 정의할 뿐 아니라 SharePoint 프로젝트 시스템에 의해 정의되고 초기화되는 기본 제공 매개 변수를 사용할 수도 있습니다.자세한 내용은 대체 가능 매개 변수을 참조하십시오.
대체 가능한 매개 변수를 Elements.xml 파일에 추가하려면
SiteColumnProjectTemplate 프로젝트의 Elements.xml 파일의 내용을 다음 XML로 바꿉니다.
<?xml version="1.0" encoding="utf-8"?> <Elements xmlns="https://schemas.microsoft.com/sharepoint/"> <Field ID="{$guid5$}" Name="$fieldname$" DisplayName="$fieldname$" Type="$selectedfieldtype$" Group="$selectedgrouptype$"> </Field> </Elements>
새로운 XML에서는 Name, DisplayName, Type 및 Group 특성의 값을 대체 가능한 사용자 지정 매개 변수로 변경합니다.
파일을 저장한 후 닫습니다.
VSIX 패키지에 마법사 추가
사이트 열 프로젝트 템플릿이 포함된 VSIX 패키지를 사용하여 마법사를 배포하려면 마법사 프로젝트와 SharePoint 명령 프로젝트에 대한 참조를 VSIX 프로젝트의 source.extension.vsixmanifest 파일에 추가합니다.
VSIX 패키지에 마법사를 추가하려면
솔루션 탐색기에 SiteColumnProjectItem 프로젝트에 대 한 바로 가기 메뉴를 엽니다의 source.extension.vsixmanifest 파일을 및 다음 선택 열기.
매니페스트 편집기에서 파일이 열립니다.
에 자산 탭 편집기의 선택은 New 단추.
를 추가 하는 새로운 자산 대화 상자가 열립니다.
에 있는 유형 목록에서 선택 Microsoft.VisualStudio.Assembly.
에 있는 원본 목록에서 선택 현재 솔루션의 프로젝트에.
에 프로젝트 목록에서 선택 ProjectTemplateWizard, 다음 선택은 확인 단추입니다.
에 자산 탭 편집기의 선택은 New 단추를 다시 클릭.
를 추가 하는 새로운 자산 대화 상자가 열립니다.
에 있는 유형 목록에서 입력 SharePoint.Commands.v4.
에 있는 원본 목록에서 선택 현재 솔루션의 프로젝트에.
에 프로젝트 목록에서 선택의 SharePointCommands 프로젝트를 하 고 선택은 확인 단추.
메뉴 표시줄에서 선택 빌드, 솔루션 빌드, 및 다음 솔루션이 오류 없이 빌드되는지 확인 합니다.
마법사 테스트
이제 마법사를 테스트할 준비가 되었습니다.우선 실험 모드의 Visual Studio 인스턴스에서 SiteColumnProjectItem 솔루션 디버깅을 시작합니다.그런 다음 실험 모드의 Visual Studio 인스턴스에서 사이트 열 프로젝트에 대한 마법사를 테스트합니다.마지막으로, 프로젝트를 빌드 및 실행하여 사이트 열이 예상대로 작동하는지 확인합니다.
솔루션 디버깅을 시작하려면
Visual Studio 관리자 자격 증명으로 다시 시작 하 고 SiteColumnProjectItem 솔루션을 엽니다.
ProjectTemplateWizard 프로젝트에 SiteColumnProjectWizard 코드 파일을 열고 다음 코드의 첫째 줄에 중단점을 추가 된 RunStarted 메서드입니다.
메뉴 표시줄에서 선택 디버깅, 예외.
에 예외 대화 상자에서 있는지 확인 하십시오의 throw 됨 및 사용자가 처리 하지 않음 확인란을 공용 언어 런타임 예외 선택을 하 고 선택의 확인 단추.
선택 하 여 디버깅을 시작 된 F5 키 또는 메뉴 모음을 선택 디버깅, 디버깅 시작.
Visual Studio Column\1.0 %userprofile%\appdata\local\microsoft\visualstudio\11.0exp\extensions\contoso\site에 있는 확장을 설치 및 Visual Studio 실험 인스턴스를 시작 합니다.프로젝트 항목에 Visual Studio이 인스턴스를 테스트 합니다.
Visual Studio에서 마법사를 테스트하려면
Visual Studio 실험적 인스턴스에서 메뉴 표시줄에서 선택 파일, New, 프로젝트.
확장은 C# 노드 또는 Visual Basic (프로젝트 템플릿을 지 원하는 언어에 따라), 노드를 확장은 SharePoint 노드를 다음 선택은 2010 노드.
프로젝트 템플릿 목록에서 선택 사이트 열, 프로젝트의 이름을 SiteColumnWizardTest, 다음 선택은 확인 단추입니다.
다른 Visual Studio 인스턴스의 코드가 이전에 RunStarted 메서드에 설정한 중단점에서 중지하는지 확인합니다.
계속을 선택 하 여 프로젝트를 디버깅 하는 F5 키 또는 메뉴 모음을 선택 디버깅, 계속.
에 SharePoint 사용자 지정 마법사디버깅에 사용 하려는 사이트의 URL을 입력 하 고 다음 선택의 다음 단추.
SharePoint 사용자 지정 마법사의 두 번째 페이지에서 다음과 같이 선택합니다.
에 있는 유형 목록에서 선택 부울.
에 있는 그룹 목록에서 선택 사용자 지정 예/아니요 열.
에 있는 이름 상자 내 예/아니요 열을 입력 하 고 다음을 선택의 마침 단추.
솔루션 탐색기, 프로젝트를 새로 나타나고 라는 프로젝트 항목이 포함 된 Field1, Visual Studio 프로젝트의 Elements.xml 파일을 편집기에서 엽니다.
마법사에서 지정한 값이 Elements.xml에 포함되어 있는지 확인합니다.
SharePoint에서 사이트 열을 테스트하려면
Visual Studio 실험적 인스턴스에서 F5 키를 선택 합니다.
사이트 열을 포장 하는 Sharepoint에 배포는 사이트는 사이트 URL 프로젝트 속성을 지정 합니다.웹 브라우저가이 사이트의 기본 페이지를 엽니다.
[!참고]
경우는 스크립트 디버깅 사용 안 함 대화 상자가 나타나면 선택은 예 프로젝트에 디버깅을 계속 하려면 단추.
에 있는 사이트 작업 메뉴를 선택 사이트 설정.
사이트 설정 페이지에서 아래에서 갤러리, 선택은 사이트 열 링크입니다.
사이트 열의 목록에 있는지 확인은 사용자 지정 예/아니요 열 라는 열을 포함 하는 그룹 내 예/아니요 열을 하 고 웹 브라우저를 닫습니다.
개발 컴퓨터 정리
프로젝트 항목의 테스트를 마쳤으면 실험 모드의 Visual Studio 인스턴스에서 프로젝트 템플릿을 제거합니다.
개발 컴퓨터를 정리하려면
Visual Studio 실험적 인스턴스에서 메뉴 표시줄에서 선택 도구, 확장 및 업데이트.
확장 및 업데이트 대화 상자가 열립니다.
확장명 목록에서 선택한 사이트 열, 다음 선택은 제거 단추입니다.
나타나는 대화 상자에서 선택 된 예 확장명을 제거 하 고 선택 확인 단추는 지금 다시 시작 단추 제거를 완료 합니다.
Visual Studio 실험적 인스턴스에서 CustomActionProjectItem 솔루션에 열려 있는 인스턴스를 모두 닫습니다.
배포 하는 방법에 대 한 Visual Studio 확장을 참조 하십시오. Visual Studio Extension 배포.
참고 항목
작업
연습: 프로젝트 템플릿을 사용하여 사이트 열 프로젝트 항목 만들기, 1부