다음을 통해 공유


연습: 항목 템플릿을 사용하여 사용자 지정 작업 프로젝트 항목 만들기, 2부

Visual Studio에서 SharePoint 프로젝트 항목의 사용자 지정 형식을 정의하여 항목 템플릿과 연결한 후에는 템플릿에 대한 마법사를 제공할 수 있습니다. 마법사를 사용하면 사용자가 템플릿을 사용하여 해당 프로젝트 항목의 새 인스턴스를 프로젝트에 추가할 때 사용자에게서 정보를 수집할 수 있습니다. 수집한 정보는 프로젝트 항목을 초기화하는 데 사용될 수 있습니다.

이 연습에서는 연습: 항목 템플릿을 사용하여 사용자 지정 작업 프로젝트 항목 만들기, 1부에서 설명한 사용자 지정 작업 프로젝트 항목에 마법사를 추가합니다. 사용자가 SharePoint 프로젝트에 사용자 지정 작업 프로젝트 항목을 추가하면 이 마법사는 사용자 지정 작업에 대한 정보(예: 사용자 지정 작업 클릭 시 이동할 위치 및 URL)를 수집하고 이 정보를 새 프로젝트 항목의 Elements.xml 파일에 추가합니다.

이 연습에서는 다음 작업을 수행합니다.

  • 항목 템플릿과 연결된 사용자 지정 SharePoint 프로젝트 항목 형식을 위한 마법사 만들기

  • Visual Studio 2010에서 SharePoint 프로젝트 항목을 위한 기본 제공 마법사와 유사한 사용자 지정 마법사 UI 정의

  • 대체 가능한 매개 변수를 사용하여 마법사에서 수집한 데이터로 SharePoint 프로젝트 파일 초기화

  • 마법사 디버깅 및 테스트

참고

https://go.microsoft.com/fwlink/?LinkId=191369에서 이 연습에 대한 완료된 프로젝트, 코드 및 기타 파일이 포함된 샘플을 다운로드할 수 있습니다.

사전 요구 사항

이 연습을 수행하려면 먼저 연습: 항목 템플릿을 사용하여 사용자 지정 작업 프로젝트 항목 만들기, 1부를 완료하여 CustomActionProjectItem 솔루션을 만들어야 합니다.

또한 개발 컴퓨터에 다음 구성 요소가 있어야 이 연습을 완료할 수 있습니다.

다음 개념을 알고 있으면 연습을 완료하는 데 도움이 되지만 반드시 필요하지는 않습니다.

마법사 프로젝트 만들기

이 연습을 완료하려면 연습: 항목 템플릿을 사용하여 사용자 지정 작업 프로젝트 항목 만들기, 1부에서 만든 CustomActionProjectItem 솔루션에 새 프로젝트를 추가해야 합니다. 이 프로젝트에서 IWizard 인터페이스를 구현하고 마법사 UI를 정의합니다.

마법사 프로젝트를 만들려면

  1. Visual Studio에서 CustomActionProjectItem 솔루션을 엽니다.

  2. 솔루션 탐색기에서 솔루션 노드를 마우스 오른쪽 단추로 클릭한 다음 추가, 새 프로젝트를 차례로 클릭합니다.

    참고

    Visual Basic 프로젝트에서는 옵션 대화 상자, 프로젝트 및 솔루션, 일반에서 솔루션 항상 표시 확인란을 선택한 경우에만 솔루션 탐색기에 솔루션 노드가 표시됩니다.

  3. 새 프로젝트 대화 상자에서 Visual C# 또는 Visual Basic 노드를 확장하고 Windows 노드를 클릭합니다.

  4. 새 프로젝트 대화 상자 맨 위의 콤보 상자에서 .NET Framework 4가 선택되어 있는지 확인합니다.

  5. WPF 사용자 정의 컨트롤 라이브러리 프로젝트 템플릿을 선택합니다.

  6. 이름 상자에 ItemTemplateWizard를 입력합니다.

  7. 확인을 클릭합니다.

    Visual Studio에서는 ItemTemplateWizard 프로젝트를 솔루션에 추가합니다.

  8. 프로젝트에서 UserControl1 항목을 삭제합니다.

마법사 프로젝트 구성

마법사를 만들기 전에 WPF 창, 코드 파일 및 어셈블리 참조를 프로젝트에 추가해야 합니다.

마법사 프로젝트를 구성하려면

  1. 솔루션 탐색기에서 ItemTemplateWizard 프로젝트 노드를 마우스 오른쪽 단추로 클릭하고 속성을 클릭합니다.

  2. 프로젝트 디자이너에서 대상 프레임워크를 .NET Framework 4 Client Profile에서 .NET Framework 4로 변경합니다. Visual C# 프로젝트에서는 응용 프로그램 탭에서 이 작업을 수행할 수 있으며, Visual Basic 프로젝트의 경우에는 컴파일 탭에서 이 작업을 수행할 수 있습니다. 자세한 내용은 방법: 특정 .NET Framework 버전 또는 프로필을 대상으로 지정을 참조하십시오.

    참고

    기본적으로 .NET Framework 4를 대상으로 하는 새 프로젝트를 만들면 프로젝트가 클라이언트 프로필을 대상으로 합니다. 이 연습에서는 완전한 .NET Framework 4가 필요합니다.

  3. ItemTemplateWizard 프로젝트에서 새 창(WPF) 항목을 프로젝트에 추가합니다. 새 항목의 이름을 WizardWindow로 지정합니다.

  4. 다음과 같은 이름의 코드 파일 두 개를 추가합니다.

    • CustomActionWizard

    • 문자열

  5. 프로젝트 메뉴에서 참조 추가를 클릭합니다.

  6. .NET 탭에서 Ctrl 키를 누르고 다음 어셈블리를 클릭한 다음 확인을 클릭합니다.

    • EnvDTE

    • Microsoft.VisualStudio.Shell.10.0

    • Microsoft.VisualStudio.TemplateWizardInterface

  7. 솔루션 탐색기에서 ItemTemplateWizard 프로젝트의 참조 폴더 아래에 있는 EnvDTE를 클릭합니다.

    참고

    Visual Basic 프로젝트에서는 옵션 대화 상자, 프로젝트 및 솔루션, 일반에서 솔루션 항상 표시 확인란을 선택한 경우에만 참조 폴더가 표시됩니다.

  8. 속성 창에서 Interop 형식 포함 속성을 False로 변경합니다.

사용자 지정 작업의 기본 위치 및 ID 문자열 정의

모든 사용자 지정 작업에는 Elements.xml 파일에 있는 CustomAction 요소의 GroupID 및 Location 특성으로 지정되는 위치 및 ID가 있습니다. 이 단계에서는 ItemTemplateWizard 프로젝트에서 이러한 특성에 지정할 수 있는 올바른 문자열을 정의합니다. 이 연습을 완료하면 사용자가 마법사에서 위치 및 ID를 선택할 경우 사용자 지정 작업 프로젝트 항목의 Elements.xml 파일에 이러한 문자열이 기록됩니다.

이 샘플에서는 복잡성을 줄이기 위해 사용 가능한 기본 위치 및 ID의 하위 집합만 지원합니다. 전체 목록은 Default Custom Action Locations and IDs를 참조하십시오.

기본 위치 및 ID 문자열을 정의하려면

  1. ItemTemplateWizard 프로젝트에서 문자열 코드 파일을 엽니다.

  2. 이 파일의 코드를 다음 코드로 바꿉니다.

    ' This sample only supports several custom action locations and their group IDs. 
    Friend Class CustomActionLocations
        Friend Const ListEdit As String = "Microsoft.SharePoint.ListEdit"
        Friend Const StandardMenu As String = "Microsoft.SharePoint.StandardMenu"
    End Class
    
    Friend Class StandardMenuGroupIds
        Friend Const Actions As String = "ActionsMenu"
        Friend Const ActionsSurvey As String = "ActionsMenuForSurvey"
        Friend Const NewMenu As String = "NewMenu"
        Friend Const Settings As String = "SettingsMenu"
        Friend Const SettingsSurvey As String = "SettingsMenuForSurvey"
        Friend Const SiteActions As String = "SiteActions"
        Friend Const Upload As String = "UploadMenu"
        Friend Const ViewSelector As String = "ViewSelectorMenu"
    End Class
    
    Friend Class ListEditGroupIds
        Friend Const Communications As String = "Communications"
        Friend Const GeneralSettings As String = "GeneralSettings"
        Friend Const Permissions As String = "Permissions"
    End Class
    
    Friend Class DefaultTextBoxStrings
        Friend Const TitleText As String = "Replace this with your title"
        Friend Const DescriptionText As String = "Replace this with your description"
        Friend Const UrlText As String = "~site/Lists/Tasks/AllItems.aspx"
    End Class
    
    
    namespace ItemTemplateWizard
    {
        // This sample only supports several custom action locations and their group IDs. 
        internal class CustomActionLocations
        {
            internal const string ListEdit = "Microsoft.SharePoint.ListEdit";
            internal const string StandardMenu = "Microsoft.SharePoint.StandardMenu";
        }
    
        internal class StandardMenuGroupIds
        {
            internal const string Actions = "ActionsMenu";
            internal const string ActionsSurvey = "ActionsMenuForSurvey";
            internal const string NewMenu = "NewMenu";
            internal const string Settings = "SettingsMenu";
            internal const string SettingsSurvey = "SettingsMenuForSurvey";
            internal const string SiteActions = "SiteActions";
            internal const string Upload = "UploadMenu";
            internal const string ViewSelector = "ViewSelectorMenu";
        }
    
        internal class ListEditGroupIds
        {
            internal const string Communications = "Communications";
            internal const string GeneralSettings = "GeneralSettings";
            internal const string Permissions = "Permissions";
        }
    
        internal class DefaultTextBoxStrings
        {
            internal const string TitleText = "Replace this with your title";
            internal const string DescriptionText = "Replace this with your description";
            internal const string UrlText = "~site/Lists/Tasks/AllItems.aspx";
        }
    }
    

마법사 UI 만들기

마법사의 UI를 정의하기 위해 XAML을 추가하고 마법사의 일부 컨트롤을 ID 문자열에 바인딩하기 위해 일부 코드를 추가합니다. 만드는 마법사는 Visual Studio 2010의 SharePoint 프로젝트에 대한 기본 제공 마법사와 유사합니다.

마법사 UI를 만들려면

  1. ItemTemplateWizard 프로젝트에서 WizardWindow.xaml 파일을 두 번 클릭하여 디자이너에서 창을 엽니다.

  2. 디자이너의 XAML 뷰에서 현재 XAML을 다음 XAML로 바꿉니다. 이 XAML에서는 제목, 사용자 지정 작업의 동작을 지정하기 위한 컨트롤 및 창 아래쪽의 탐색 단추가 포함된 UI를 정의합니다.

    참고

    이 XAML을 프로젝트에 추가하면 프로젝트에서 컴파일 오류가 발생합니다. 이러한 오류는 이후 단계에서 코드를 추가하면 사라집니다.

    <ui:DialogWindow x:Class="ItemTemplateWizard.WizardWindow"
                     xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
                     xmlns:ui="clr-namespace:Microsoft.VisualStudio.PlatformUI;assembly=Microsoft.VisualStudio.Shell.10.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 Grid.Row="0" Content="Configure the Custom Action" Name="pageHeaderLabel" HorizontalAlignment="Left" 
                       VerticalAlignment="Center" Margin="18,0,0,0" FontWeight="ExtraBold" />
            </Grid>
            <Grid Grid.Row="1" Name="mainGrid">
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="20*" />
                    <ColumnDefinition Width="Auto" />
                    <ColumnDefinition Width="400*" />
                </Grid.ColumnDefinitions>
                <Grid.RowDefinitions>
                    <RowDefinition Height="Auto" />
                    <RowDefinition Height="Auto" />
                    <RowDefinition Height="Auto" />
                    <RowDefinition Height="Auto" />
                    <RowDefinition Height="Auto" />
                </Grid.RowDefinitions>
                <StackPanel Grid.Row="0" Grid.Column="1" Orientation="Vertical">
                    <Label Margin="0,20,0,0" Content="Location:" Name="locationLabel" FontWeight="Bold" />
                    <RadioButton Content="_List Edit" Margin="5,0,0,0" Name="listEditRadioButton" 
                                 Checked="listEditRadioButton_Checked" FontWeight="Normal"  />
                    <RadioButton Content="_Standard Menu" Margin="5,5,0,0" Name="standardMenuRadioButton" 
                                 Checked="standardMenuRadioButton_Checked" FontWeight="Normal" />
                </StackPanel>
                <Label Grid.Row="1" Grid.Column="1" Margin="0,15,0,0" Content="_Group ID:" Name="groupIdLabel" 
                       FontWeight="Bold" Target="{Binding ElementName=idComboBox}" />
                <ComboBox Grid.Row="1" Grid.Column="2" HorizontalAlignment="Left" Margin="0,15,0,0" Height="23" 
                          Width="253" Name="idComboBox" IsEditable="False" IsSynchronizedWithCurrentItem="True" />
                <Label Grid.Row="2" Grid.Column="1" Margin="0,15,0,0" Content="_Title:" Name="titleLabel" 
                       FontWeight="Bold" Target="{Binding ElementName=titleTextBox}" />
                <TextBox Grid.Row="2" Grid.Column="2" HorizontalAlignment="Left" Margin="0,15,0,0" Height="23" 
                         Name="titleTextBox" Width="410" Text="" />
                <Label Grid.Row="3" Grid.Column="1" Margin="0,15,0,0" Content="_Description:" Name="descriptionLabel" 
                       FontWeight="Bold" Target="{Binding ElementName=descriptionTextBox}" />
                <TextBox Grid.Row="3" Grid.Column="2" HorizontalAlignment="Left" Margin="0,15,0,0" Height="23" 
                         Name="descriptionTextBox" Width="410" Text="" />
                <Label Grid.Row="4" Grid.Column="1" Margin="0,15,0,0" Content="_URL:" Height="28" Name="urlLabel" 
                       FontWeight="Bold" Target="{Binding ElementName=urlTextBox}" />
                <TextBox Grid.Row="4" Grid.Column="2" HorizontalAlignment="Left" Margin="0,15,0,0" Height="23" 
                         Name="urlTextBox" Width="410" Text="" />
            </Grid>
            <Rectangle Grid.Row="2" Name="separatorRectangle" Fill="White"  />
            <StackPanel Grid.Row="3" Name="navigationPanel" Orientation="Horizontal">
                <Button Content="_Finish" Margin="500,0,0,0" Height="25" Name="finishButton" Width="85" 
                        Click="finishButton_Click" IsDefault="True" />
                <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 대화 상자와 일관성 있는 스타일을 사용하고 발생할 수 있는 모달 대화 상자 문제를 방지하기 위해 이 클래스에서 대화 상자를 파생시키는 것이 좋습니다. 자세한 내용은 How to: Create and Manage Dialog Boxes를 참조하십시오.

  3. Visual Basic 프로젝트를 개발하는 중이면 Window 요소의 x:Class 특성에 있는 WizardWindow 클래스 이름에서 ItemTemplateWizard 네임스페이스를 제거합니다. 이 네임스페이스는 XAML의 첫 번째 줄에 있습니다. 지금까지 작업을 마친 후의 첫 번째 줄은 다음과 같습니다.

    <Window x:Class="WizardWindow"
    
  4. WizardWindow.xaml 파일의 코드 숨김 파일을 엽니다.

  5. 이 파일의 코드를 다음 코드로 바꿉니다.

    Public Class WizardWindow
        Private standardMenuGroups As List(Of String)
        Private listEditGroups As List(Of String)
        Private standardMenuGroupIdBinding As Binding
        Private listEditGroupIdBinding As Binding
        Private standardMenuGroupIdBindingView As ListCollectionView
        Private listEditGroupIdBindingView As ListCollectionView
    
        Private Sub Window_Loaded(ByVal sender As Object, ByVal e As RoutedEventArgs)
            standardMenuGroups = New List(Of String) From {
                StandardMenuGroupIds.Actions,
                StandardMenuGroupIds.ActionsSurvey,
                StandardMenuGroupIds.NewMenu,
                StandardMenuGroupIds.Settings,
                StandardMenuGroupIds.SettingsSurvey,
                StandardMenuGroupIds.SiteActions,
                StandardMenuGroupIds.Upload,
                StandardMenuGroupIds.ViewSelector}
            listEditGroups = New List(Of String) From {
                ListEditGroupIds.Communications,
                ListEditGroupIds.GeneralSettings,
                ListEditGroupIds.Permissions}
    
            standardMenuGroupIdBinding = New Binding()
            standardMenuGroupIdBinding.Source = standardMenuGroups
            listEditGroupIdBinding = New Binding()
            listEditGroupIdBinding.Source = listEditGroups
    
            standardMenuGroupIdBindingView = CType(CollectionViewSource.GetDefaultView(standardMenuGroups), ListCollectionView)
            listEditGroupIdBindingView = CType(CollectionViewSource.GetDefaultView(listEditGroups), ListCollectionView)
    
            standardMenuRadioButton.IsChecked = True
        End Sub
    
        Private Sub standardMenuRadioButton_Checked(ByVal sender As Object, ByVal e As RoutedEventArgs)
            BindingOperations.ClearBinding(idComboBox, ComboBox.ItemsSourceProperty)
            idComboBox.SetBinding(ComboBox.ItemsSourceProperty, standardMenuGroupIdBinding)
            standardMenuGroupIdBindingView.MoveCurrentToFirst()
        End Sub
    
        Private Sub listEditRadioButton_Checked(ByVal sender As Object, ByVal e As RoutedEventArgs)
            BindingOperations.ClearBinding(idComboBox, ComboBox.ItemsSourceProperty)
            idComboBox.SetBinding(ComboBox.ItemsSourceProperty, listEditGroupIdBinding)
            listEditGroupIdBindingView.MoveCurrentToFirst()
        End Sub
    
        Private Sub finishButton_Click(ByVal sender As Object, ByVal e As RoutedEventArgs)
            Me.DialogResult = True
            Me.Close()
        End Sub
    End Class
    
    using System.Collections.Generic;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Data;
    using Microsoft.VisualStudio.PlatformUI;
    
    namespace ItemTemplateWizard
    {
        public partial class WizardWindow : DialogWindow
        {
            private List<string> standardMenuGroups;
            private List<string> listEditGroups;
            private Binding standardMenuGroupIdBinding;
            private Binding listEditGroupIdBinding;
            private ListCollectionView standardMenuGroupIdBindingView;
            private ListCollectionView listEditGroupIdBindingView;
    
            public WizardWindow()
            {
                InitializeComponent();
            }
    
            private void Window_Loaded(object sender, RoutedEventArgs e)
            {
                standardMenuGroups = new List<string>() { 
                    StandardMenuGroupIds.Actions,
                    StandardMenuGroupIds.ActionsSurvey,
                    StandardMenuGroupIds.NewMenu, 
                    StandardMenuGroupIds.Settings, 
                    StandardMenuGroupIds.SettingsSurvey,
                    StandardMenuGroupIds.SiteActions, 
                    StandardMenuGroupIds.Upload, 
                    StandardMenuGroupIds.ViewSelector };
                listEditGroups = new List<string>() { 
                    ListEditGroupIds.Communications, 
                    ListEditGroupIds.GeneralSettings,
                    ListEditGroupIds.Permissions };
    
                standardMenuGroupIdBinding = new Binding();
                standardMenuGroupIdBinding.Source = standardMenuGroups;
                listEditGroupIdBinding = new Binding();
                listEditGroupIdBinding.Source = listEditGroups;
    
                standardMenuGroupIdBindingView = (ListCollectionView)CollectionViewSource.GetDefaultView(standardMenuGroups);
                listEditGroupIdBindingView = (ListCollectionView)CollectionViewSource.GetDefaultView(listEditGroups);
    
                standardMenuRadioButton.IsChecked = true;
            }
    
            private void standardMenuRadioButton_Checked(object sender, RoutedEventArgs e)
            {
                BindingOperations.ClearBinding(idComboBox, ComboBox.ItemsSourceProperty);
                idComboBox.SetBinding(ComboBox.ItemsSourceProperty, standardMenuGroupIdBinding);
                standardMenuGroupIdBindingView.MoveCurrentToFirst();
            }
    
            private void listEditRadioButton_Checked(object sender, RoutedEventArgs e)
            {
                BindingOperations.ClearBinding(idComboBox, ComboBox.ItemsSourceProperty);
                idComboBox.SetBinding(ComboBox.ItemsSourceProperty, listEditGroupIdBinding);
                listEditGroupIdBindingView.MoveCurrentToFirst();
            }
    
            private void finishButton_Click(object sender, RoutedEventArgs e)
            {
                this.DialogResult = true;
                this.Close();
            }
        }
    }
    

마법사 구현

IWizard 인터페이스를 구현하여 마법사의 기능을 정의합니다.

마법사를 구현하려면

  1. ItemTemplateWizard 프로젝트에서 CustomActionWizard 코드 파일을 엽니다.

  2. 이 파일의 코드를 다음 코드로 바꿉니다.

    Imports EnvDTE
    Imports Microsoft.VisualStudio.TemplateWizard
    Imports System
    Imports System.Collections.Generic
    
    Public Class CustomActionWizard
        Implements IWizard
    
        Private wizardPage As WizardWindow
    
    #Region "IWizard Methods"
    
        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
            wizardPage = New WizardWindow()
            Dim dialogCompleted? As Boolean = wizardPage.ShowModal()
    
            If (dialogCompleted = True) Then
                PopulateReplacementDictionary(replacementsDictionary)
            Else
                Throw New WizardCancelledException()
            End If
        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 implemented in this example.
        Public Sub BeforeOpeningFile(ByVal projectItem As ProjectItem) _
            Implements IWizard.BeforeOpeningFile
        End Sub
    
        Public Sub ProjectFinishedGenerating(ByVal project As Project) _
            Implements IWizard.ProjectFinishedGenerating
        End Sub
    
        Public Sub ProjectItemFinishedGenerating(ByVal projectItem As ProjectItem) _
            Implements IWizard.ProjectItemFinishedGenerating
        End Sub
    
        Public Sub RunFinished() Implements IWizard.RunFinished
        End Sub
    
    #End Region
    
        Private Sub PopulateReplacementDictionary(ByVal replacementsDictionary As Dictionary(Of String, String))
    
            ' Fill in the replacement values from the UI selections on the wizard page. These values are automatically inserted
            ' into the Elements.xml file for the custom action.
            Dim locationValue As String = If(wizardPage.standardMenuRadioButton.IsChecked,
                    CustomActionLocations.StandardMenu, CustomActionLocations.ListEdit)
            replacementsDictionary.Add("$LocationValue$", locationValue)
            replacementsDictionary.Add("$GroupIdValue$", CType(wizardPage.idComboBox.SelectedItem, String))
            replacementsDictionary.Add("$IdValue$", Guid.NewGuid().ToString())
    
            Dim titleText As String = DefaultTextBoxStrings.TitleText
            If False = String.IsNullOrEmpty(wizardPage.titleTextBox.Text) Then
                titleText = wizardPage.titleTextBox.Text
            End If
    
            Dim descriptionText As String = DefaultTextBoxStrings.DescriptionText
            If False = String.IsNullOrEmpty(wizardPage.descriptionTextBox.Text) Then
                descriptionText = wizardPage.descriptionTextBox.Text
            End If
    
            Dim urlText As String = DefaultTextBoxStrings.UrlText
            If False = String.IsNullOrEmpty(wizardPage.urlTextBox.Text) Then
                urlText = wizardPage.urlTextBox.Text
            End If
    
            replacementsDictionary.Add("$TitleValue$", titleText)
            replacementsDictionary.Add("$DescriptionValue$", descriptionText)
            replacementsDictionary.Add("$UrlValue$", urlText)
        End Sub
    End Class
    
    using EnvDTE;
    using Microsoft.VisualStudio.TemplateWizard;
    using System;
    using System.Collections.Generic;
    
    namespace ItemTemplateWizard
    {
        public class CustomActionWizard : IWizard
        {
            private WizardWindow wizardPage;
    
            public CustomActionWizard()
            {
            }
    
            #region IWizard Methods
    
            public void RunStarted(object automationObject, Dictionary<string, string> replacementsDictionary, 
                WizardRunKind runKind, object[] customParams)
            {
                wizardPage = new WizardWindow();
                Nullable<bool> dialogCompleted = wizardPage.ShowModal();
    
                if (dialogCompleted == true)
                {
                    PopulateReplacementDictionary(replacementsDictionary);
                }
                else
                {
                    throw new WizardCancelledException();
                }
            }
    
            // 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 implemented in this example.
            public void BeforeOpeningFile(ProjectItem projectItem)
            {
            }
    
            public void ProjectFinishedGenerating(Project project)
            {
            }
    
            public void ProjectItemFinishedGenerating(ProjectItem projectItem)
            {
            }
    
            public void RunFinished()
            {
            }
    
            #endregion
    
            private void PopulateReplacementDictionary(Dictionary<string, string> replacementsDictionary)
            {
                // Fill in the replacement values from the UI selections on the wizard page. These values are automatically inserted
                // into the Elements.xml file for the custom action.
                string locationValue = (bool)wizardPage.standardMenuRadioButton.IsChecked ?
                    CustomActionLocations.StandardMenu : CustomActionLocations.ListEdit;
                replacementsDictionary.Add("$LocationValue$", locationValue);
                replacementsDictionary.Add("$GroupIdValue$", (string)wizardPage.idComboBox.SelectedItem);
                replacementsDictionary.Add("$IdValue$", Guid.NewGuid().ToString());
    
                string titleText = DefaultTextBoxStrings.TitleText;
                if (!String.IsNullOrEmpty(wizardPage.titleTextBox.Text))
                {
                    titleText = wizardPage.titleTextBox.Text;
                }
    
                string descriptionText = DefaultTextBoxStrings.DescriptionText;
                if (!String.IsNullOrEmpty(wizardPage.descriptionTextBox.Text))
                {
                    descriptionText = wizardPage.descriptionTextBox.Text;
                }
    
                string urlText = DefaultTextBoxStrings.UrlText;
                if (!String.IsNullOrEmpty(wizardPage.urlTextBox.Text))
                {
                    urlText = wizardPage.urlTextBox.Text;
                }
    
                replacementsDictionary.Add("$TitleValue$", titleText);
                replacementsDictionary.Add("$DescriptionValue$", descriptionText);
                replacementsDictionary.Add("$UrlValue$", urlText);
            }
        }
    }
    

검사점

이 연습의 이전 단계를 통해 마법사를 위한 모든 코드가 프로젝트에 포함되었습니다. 프로젝트를 빌드하여 오류 없이 컴파일되는지 확인합니다.

프로젝트를 빌드하려면

  • 빌드 메뉴에서 솔루션 빌드를 선택합니다.

마법사를 항목 템플릿과 연결

마법사를 구현했으므로 이 마법사를 사용자 지정 작업 항목 템플릿과 연결해야 합니다. 이렇게 하려면 세 가지 주요 단계를 완료해야 합니다.

  1. 강력한 이름으로 마법사 어셈블리에 서명합니다.

  2. 마법사 어셈블리의 공개 키 토큰을 가져옵니다.

  3. 사용자 지정 작업 항목 템플릿의 .vstemplate 파일에서 마법사 어셈블리에 대한 참조를 추가합니다.

강력한 이름으로 마법사 어셈블리에 서명하려면

  1. 솔루션 탐색기에서 ItemTemplateWizard 프로젝트 노드를 마우스 오른쪽 단추로 클릭하고 속성을 클릭합니다.

  2. 서명 탭을 클릭합니다.

  3. 어셈블리 서명 확인란을 선택합니다.

  4. 강력한 이름 키 파일 선택 드롭다운 목록에서 **<새로 만들기...>**를 선택합니다.

  5. 강력한 이름 키 만들기 대화 상자에서 이름을 입력하고 암호로 내 키 파일 보호 확인란의 선택을 취소합니다.

  6. 확인을 클릭합니다.

  7. 빌드 메뉴에서 솔루션 빌드를 선택합니다.

마법사 어셈블리의 공개 키 토큰을 가져오려면

  1. Visual Studio 명령 프롬프트 창을 엽니다.

  2. 다음 명령을 실행합니다. path to wizard assembly를 개발 컴퓨터에서 ItemTemplateWizard 프로젝트를 위해 빌드된 ItemTemplateWizard.dll 어셈블리의 전체 경로로 바꿉니다.

    sn.exe -T path to wizard assembly
    

    ItemTemplateWizard.dll 어셈블리의 공개 키 토큰은 Visual Studio 명령 프롬프트 창에 기록됩니다.

  3. Visual Studio 명령 프롬프트 창을 계속 열어 둡니다. 공개 키 토큰은 다음 절차 중에 필요합니다.

마법사 어셈블리에 대한 참조를 .vstemplate 파일에 추가하려면

  1. 솔루션 탐색기에서 항목 템플릿 프로젝트 노드를 확장하고 ItemTemplate.vstemplate 파일을 엽니다.

  2. 파일의 끝 부분에서 </TemplateContent> 및 </VSTemplate> 태그 사이에 다음 WizardExtension 요소를 추가합니다. PublicKeyToken 특성의 your token 값을 이전 절차에서 가져온 공개 키 토큰으로 바꿉니다.

    <WizardExtension>
      <Assembly>ItemTemplateWizard, Version=1.0.0.0, Culture=neutral, PublicKeyToken=your token</Assembly>
      <FullClassName>ItemTemplateWizard.CustomActionWizard</FullClassName>
    </WizardExtension>
    

    WizardExtension 요소에 대한 자세한 내용은 WizardExtension 요소(Visual Studio 템플릿)를 참조하십시오.

  3. 파일을 저장한 후 닫습니다.

항목 템플릿의 Elements.xml 파일에 대체 가능한 매개 변수 추가

대체 가능한 매개 변수 여러 개를 ItemTemplate 프로젝트의 Elements.xml 파일에 추가합니다. 이러한 매개 변수는 앞에서 정의한 CustomActionWizard 클래스의 PopulateReplacementDictionary 메서드에서 초기화됩니다. 사용자가 프로젝트에 사용자 지정 작업 프로젝트 항목을 추가하면 Visual Studio에서는 자동으로 새 프로젝트 항목의 Elements.xml 파일에 있는 이러한 매개 변수를 마법사에서 지정한 값으로 바꿉니다.

대체 가능한 매개 변수는 달러 기호($) 문자로 시작하고 끝나는 토큰입니다. 대체 가능한 매개 변수를 직접 정의할 뿐 아니라 SharePoint 프로젝트 시스템에 의해 정의되고 초기화되는 기본 제공 매개 변수를 사용할 수도 있습니다. 자세한 내용은 대체 가능 매개 변수를 참조하십시오.

대체 가능한 매개 변수를 Elements.xml 파일에 추가하려면

  1. ItemTemplate 프로젝트에서 Elements.xml 파일을 엽니다.

  2. 이 파일의 내용을 다음 XML로 바꿉니다.

    <?xml version="1.0" encoding="utf-8" ?>
    <Elements Id="$guid8$" xmlns="https://schemas.microsoft.com/sharepoint/">
      <CustomAction Id="$IdValue$"
                    GroupId="$GroupIdValue$"
                    Location="$LocationValue$"
                    Sequence="1000"
                    Title="$TitleValue$"
                    Description="$DescriptionValue$" >
        <UrlAction Url="$UrlValue$"/>
      </CustomAction>
    </Elements>
    

    새로운 XML은 Id, GroupId, Location, Description 및 Url 특성의 값을 대체 가능한 매개 변수로 변경합니다.

  3. 파일을 저장한 후 닫습니다.

VSIX 패키지에 마법사 추가

프로젝트 항목을 포함하는 VSIX 패키지를 사용하여 마법사를 배포하려면 마법사 프로젝트에 대한 참조를 VSIX 프로젝트의 source.extension.vsixmanifest 파일에 추가합니다.

VSIX 패키지에 마법사를 추가하려면

  1. 솔루션 탐색기에서 CustomActionProjectItem 프로젝트의 source.extension.vsixmanifest 파일을 두 번 클릭합니다.

    매니페스트 편집기에서 파일이 열립니다.

  2. 편집기의 콘텐츠 섹션에서 콘텐츠 추가 단추를 클릭합니다.

  3. 콘텐츠 추가 대화 상자의 콘텐츠 형식을 선택하십시오. 목록 상자에서 템플릿 마법사를 선택합니다.

  4. 소스 선택에서 프로젝트 라디오 단추를 클릭하고 그 옆에 있는 목록 상자에서 ItemTemplateWizard를 선택합니다.

  5. 확인을 클릭합니다.

  6. 빌드 메뉴에서 솔루션 빌드를 클릭합니다. 솔루션이 오류 없이 컴파일되는지 확인합니다.

마법사 테스트

이제 마법사를 테스트할 준비가 되었습니다. 우선 실험 모드의 Visual Studio 인스턴스에서 CustomActionProjectItem 솔루션 디버깅을 시작합니다. 그런 다음 실험 모드의 Visual Studio 인스턴스에서 SharePoint 프로젝트의 사용자 지정 프로젝트 항목에 대해 마법사를 테스트합니다. 마지막으로, SharePoint 프로젝트를 빌드 및 실행하여 사용자 지정 작업이 예상대로 작동하는지 확인합니다.

솔루션 디버깅을 시작하려면

  1. 관리자 권한으로 Visual Studio를 다시 시작하고 CustomActionProjectItem 솔루션을 엽니다.

  2. ItemTemplateWizard 프로젝트에서 CustomActionWizard 코드 파일을 열고 RunStarted 메서드의 코드 첫 줄에 중단점을 추가합니다.

  3. 디버그 메뉴에서 예외를 클릭합니다.

  4. 예외 대화 상자에서 Common Language Runtime Exceptions에 대해 Throw됨사용자가 처리하지 않음 확인란의 선택이 취소되어 있는지 확인합니다.

  5. 확인을 클릭합니다.

  6. F5 키를 눌러 디버깅을 시작합니다.

    Visual Studio에서는 확장을 %UserProfile%\AppData\Local\Microsoft\VisualStudio\10.0Exp\Extensions\Contoso\Custom Action Project Item\1.0에 설치하고 실험 모드의 Visual Studio 인스턴스를 시작합니다. 이 Visual Studio 인스턴스에서 프로젝트 항목을 테스트합니다.

Visual Studio에서 마법사를 테스트하려면

  1. 실험 모드의 Visual Studio 인스턴스에서 파일 메뉴의 새로 만들기를 가리킨 다음 프로젝트를 클릭합니다.

  2. 항목 템플릿에서 지원하는 언어에 따라 Visual C# 또는 Visual Basic을 확장하고 SharePoint를 확장한 다음 2010을 클릭합니다.

  3. 프로젝트 템플릿 목록에서 빈 프로젝트를 클릭합니다.

  4. 이름 상자에 CustomActionWizardTest를 입력합니다.

  5. 확인을 클릭합니다.

  6. SharePoint 사용자 지정 마법사에서 디버깅에 사용할 사이트의 URL을 입력하고 마침을 클릭합니다.

  7. 솔루션 탐색기에서 프로젝트 노드를 마우스 오른쪽 단추로 클릭하고 추가를 가리킨 다음 새 항목을 클릭합니다.

  8. 새 항목 추가 대화 상자의 SharePoint 노드 아래에서 2010 노드를 클릭합니다.

  9. 프로젝트 항목 목록에서 사용자 지정 작업을 클릭한 다음 추가를 클릭합니다.

  10. 다른 Visual Studio 인스턴스의 코드가 이전에 RunStarted 메서드에 설정한 중단점에서 중지하는지 확인합니다. F5 키를 눌러 프로젝트를 계속 디버깅합니다.

  11. 마법사에서 다음과 같이 선택합니다.

    • Location에서 List Edit을 클릭합니다.

    • Group ID에 대해 Communications를 클릭합니다.

    • Title에 대해 SharePoint Developer Center를 입력합니다.

    • Description에 대해 Opens the SharePoint Developer Center Web site를 입력합니다.

    • URL에 대해 https://msdn.microsoft.com/sharepoint/default.aspx를 입력합니다.

  12. 마침을 클릭합니다.

    CustomAction1이라는 새 항목이 프로젝트에 추가되고 Elements.xml 파일이 편집기에서 열립니다. 마법사에서 지정한 값이 Elements.xml에 포함되어 있는지 확인합니다.

SharePoint에서 사용자 지정 작업을 테스트하려면

  1. 실험 모드의 Visual Studio 인스턴스에서 F5 키를 누릅니다. 사용자 지정 작업이 패키징되어 프로젝트의 사이트 URL 속성에 지정된 SharePoint 사이트로 배포됩니다. 이 사이트의 기본 페이지가 웹 브라우저에서 열립니다.

    참고

    스크립트 디버깅 사용 안 함 대화 상자가 표시되면 를 클릭하여 프로젝트를 계속 디버깅합니다.

  2. 빠른 실행 영역에서 작업을 클릭합니다.

  3. 리본 메뉴에서 목록 탭을 클릭합니다.

  4. 설정 그룹에서 목록 설정을 클릭합니다.

  5. 페이지 위쪽 근처의 Communications 제목 아래에서 링크가 SharePoint Developer Center 텍스트와 함께 나타나는지 확인합니다.

  6. SharePoint Developer Center 링크를 클릭합니다. 웹 사이트 https://msdn.microsoft.com/sharepoint/default.aspx가 브라우저에서 열리는지 확인합니다.

  7. 웹 브라우저를 닫습니다.

개발 컴퓨터 정리

프로젝트 항목의 테스트를 마쳤으면 실험 모드의 Visual Studio 인스턴스에서 프로젝트 항목 템플릿을 제거합니다.

개발 컴퓨터를 정리하려면

  1. 실험 모드의 Visual Studio 인스턴스에서 도구 메뉴의 확장 관리자를 클릭합니다.

    확장 관리자 대화 상자가 열립니다.

  2. 확장 목록에서 Custom Action Project Item을 클릭한 다음 제거를 클릭합니다.

  3. 나타나는 대화 상자에서 를 클릭하여 확장을 제거합니다.

  4. 지금 다시 시작을 클릭하여 제거를 완료합니다.

  5. Visual Studio의 두 인스턴스, 즉 실험 모드의 인스턴스와 CustomActionProjectItem 솔루션이 열려 있는 Visual Studio 인스턴스를 모두 닫습니다.

참고 항목

작업

연습: 항목 템플릿을 사용하여 사용자 지정 작업 프로젝트 항목 만들기, 1부

방법: 프로젝트 템플릿에 마법사 사용

참조

Visual Studio 템플릿 스키마 참조

IWizard

기타 리소스

사용자 지정 SharePoint 프로젝트 항목 형식 정의

SharePoint 프로젝트 항목에 대한 항목 템플릿 및 프로젝트 템플릿 만들기

Default Custom Action Locations and IDs