Share via


Walkthrough: Create a custom action project item with an item template, part 2

Applies to: yesVisual Studio noVisual Studio for Mac

Note

This article applies to Visual Studio 2017. If you're looking for the latest Visual Studio documentation, see Visual Studio documentation. We recommend upgrading to the latest version of Visual Studio. Download it here

After you define a custom type of SharePoint project item and associate it with an item template in Visual Studio, you might also want to provide a wizard for the template. You can use the wizard to collect information from users when they use your template to add a new instance of the project item to a project. The information that you collect can be used to initialize the project item.

In this walkthrough, you will add a wizard to the Custom Action project item that is demonstrated in Walkthrough: Create a custom action project item with an item template, Part 1. When a user adds a Custom Action project item to a SharePoint project, the wizard collects information about the custom action (such as its location and the URL to navigate to when an end user chooses it) and adds this information to the Elements.xml file in the new project item.

This walkthrough demonstrates the following tasks:

  • Creating a wizard for a custom SharePoint project item type that is associated with an item template.

  • Defining a custom wizard UI that resembles the built-in wizards for SharePoint project items in Visual Studio.

  • Using replaceable parameters to initialize SharePoint project files with data that you collect in the wizard.

  • Debugging and testing the wizard.

Note

You can download a sample from Github that shows how to create custom activities for a workflow.

Prerequisites

To perform this walkthrough, you must first create the CustomActionProjectItem solution by completing Walkthrough: Create a custom action project item with an item template, Part 1.

You also need the following components on the development computer to complete this walkthrough:

  • Supported editions of Windows, SharePoint, and Visual Studio.

  • The Visual Studio SDK. This walkthrough uses the VSIX Project template in the SDK to create a VSIX package to deploy the project item. For more information, see Extend the SharePoint tools in Visual Studio.

    Knowledge of the following concepts is helpful, but not required, to complete the walkthrough:

  • Wizards for project and item templates in Visual Studio. For more information, see How to: Use Wizards with Project Templates and the IWizard interface.

  • Custom actions in SharePoint. For more information, see Custom Action.

Create the wizard project

To complete this walkthrough, you must add a project to the CustomActionProjectItem solution that you created in Walkthrough: Create a custom action project item with an item template, Part 1. You will implement the IWizard interface and define the wizard UI in this project.

To create the wizard project

  1. In Visual Studio, open the CustomActionProjectItem solution

  2. In Solution Explorer, open the shortcut menu for the solution node, choose Add, and then choose New Project.

  3. In the New Project dialog box, expand the Visual C# or Visual Basic nodes, and then choose the Windows node.

  4. At the top of the New Project dialog box, make sure that .NET Framework 4.5 is chosen in the list of versions of the .NET Framework.

  5. Choose the WPF User Control Library project template, name the project ItemTemplateWizard, and then choose the OK button.

    Visual Studio adds the ItemTemplateWizard project to the solution.

  6. Delete the UserControl1 item from the project.

Configure the wizard project

Before you create the wizard, you must add a Windows Presentation Foundation (WPF) window, a code file, and assembly references to the project.

To configure the wizard project

  1. In Solution Explorer, open the shortcut menu from the ItemTemplateWizard project node, and then choose Properties.

  2. In the Project Designer, make sure that the target framework is set to .NET Framework 4.5.

    For Visual C# projects, you can set this value on the Application tab. For Visual Basic projects, you can set this value on the Compile tab. For more information, see How to: Target a Version of the .NET Framework.

  3. In the ItemTemplateWizard project, add a Window (WPF) item to the project, and then name the item WizardWindow.

  4. Add two code files that are named CustomActionWizard and Strings.

  5. Open the shortcut menu for the ItemTemplateWizard project, and then choose Add Reference.

  6. In the Reference Manager - ItemTemplateWizard dialog box, under the Assemblies node, choose the Extensions node.

  7. Select the check boxes next to the following assemblies, and then choose the OK button:

    • EnvDTE

    • Microsoft.VisualStudio.Shell.11.0

    • Microsoft.VisualStudio.TemplateWizardInterface

  8. In Solution Explorer, in the References folder for the ItemTemplateWizard project, choose the EnvDTE reference.

  9. In the Properties window, change the value of the Embed Interop Types property to False.

Define the default location and ID strings for custom actions

Every custom action has a location and ID that is specified in the GroupID and Location attributes of the CustomAction element in the Elements.xml file. In this step, you define some of the valid strings for these attributes in the ItemTemplateWizard project. When you complete this walkthrough, these strings are written to the Elements.xml file in the Custom Action project item when users specify a location and an ID in the wizard.

For simplicity, this sample supports only a subset of the available default locations and IDs. For a full list, see Default Custom Action Locations and IDs.

To define the default location and ID strings

  1. open.

  2. In the ItemTemplateWizard project, replace the code in the Strings code file with the following code.

    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";
        }
    }
    
    ' 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
    

Create the wizard UI

Add XAML to define the UI of the wizard, and add some code to bind some of the controls in the wizard to the ID strings. The wizard that you create resembles the built-in wizard for SharePoint projects in Visual Studio.

To create the wizard UI

  1. In the ItemTemplateWizard project, open the shortcut menu for the WizardWindow.xaml file, and then choose Open to open the window in the designer.

  2. In the XAML view, replace the current XAML with the following XAML. The XAML defines a UI that includes a heading, controls for specifying the behavior of the custom action, and navigation buttons at the bottom of the window.

    Note

    Your project will have some compile errors after you add this code. These errors will go away when you add code in later steps.

    <ui:DialogWindow x:Class="ItemTemplateWizard.WizardWindow"
                     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                     xmlns:ui="clr-namespace:Microsoft.VisualStudio.PlatformUI;assembly=Microsoft.VisualStudio.Shell.11.0"
                     xmlns:x="http://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>
    

    Note

    The window that's created in this XAML is derived from the DialogWindow base class. When you add a custom WPF dialog box to Visual Studio, we recommend that you derive your dialog box from this class to have consistent styling with other dialog boxes in Visual Studio and to avoid issues that might otherwise occur with modal dialog boxes. For more information, see Creating and Managing Modal Dialog Boxes.

  3. If you're developing a Visual Basic project, remove the ItemTemplateWizard namespace from the WizardWindow class name in the x:Class attribute of the Window element. This element is in the first line of the XAML. When you're done, the first line should resemble the following code:

    <Window x:Class="WizardWindow"
    
  4. In the code-behind file for the WizardWindow.xaml file, replace the current code with the following code.

    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();
            }
        }
    }
    

Implement the wizard

Define the functionality of the wizard by implementing the IWizard interface.

To implement the wizard

  1. In the ItemTemplateWizard project, open the CustomActionWizard code file, and then replace the current code in this file with the following code:

    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);
            }
        }
    }
    
    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
    

Checkpoint

At this point in the walkthrough, all the code for the wizard is now in the project. Build the project to make sure that it compiles without errors.

To build your project

  1. On the menu bar, choose Build > Build Solution.

Associate the wizard with the item template

Now that you have implemented the wizard, you must associate it with the Custom Action item template by completing three main steps:

  1. Sign the wizard assembly with a strong name.

  2. Get the public key token for the wizard assembly.

  3. Add a reference to the wizard assembly in the .vstemplate file for the Custom Action item template.

To sign the wizard assembly with a strong name

  1. In Solution Explorer, open the shortcut menu from the ItemTemplateWizard project node, and then choose Properties.

  2. On the Signing tab, select the Sign the assembly check box.

  3. In the Choose a strong name key file list, choose <New...>.

  4. In the Create Strong Name Key dialog box, enter a name, clear the Protect my key file with a password check box, and then choose the OK button.

  5. On the menu bar, choose Build > Build Solution.

To get the public key token for the wizard assembly

  1. In a Visual Studio Command Prompt window, run the following command, replacing PathToWizardAssembly with the full path to the built ItemTemplateWizard.dll assembly for the ItemTemplateWizard project on your development computer.

    sn.exe -T PathToWizardAssembly
    

    The public key token for the ItemTemplateWizard.dll assembly is written to the Visual Studio Command Prompt window.

  2. Keep the Visual Studio Command Prompt window open. You'll need the public key token to complete the next procedure.

To add a reference to the wizard assembly in the .vstemplate file

  1. In Solution Explorer, expand the ItemTemplate project node, and then open the ItemTemplate.vstemplate file.

  2. Near the end of the file, add the following WizardExtension element between the </TemplateContent> and </VSTemplate> tags. Replace the YourToken value of the PublicKeyToken attribute with the public key token that you obtained in the previous procedure.

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

    For more information about the WizardExtension element, see WizardExtension Element (Visual Studio Templates).

  3. Save and close the file.

Add replaceable parameters to the Elements.xml file in the item template

Add several replaceable parameters to the Elements.xml file in the ItemTemplate project. These parameters are initialized in the PopulateReplacementDictionary method in the CustomActionWizard class that you defined earlier. When a user adds a Custom Action project item to a project, Visual Studio automatically replaces these parameters in the Elements.xml file in the new project item with the values that they specified in the wizard.

A replaceable parameter is a token that starts and ends with the dollar sign ($) character. In addition to defining your own replaceable parameters, you can use built-in parameters that the SharePoint project system defines and initializes. For more information, see Replaceable parameters.

To add replaceable parameters to the Elements.xml file

  1. In the ItemTemplate project, replace the contents of the Elements.xml file with the following XML.

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

    The new XML changes the values of the Id, GroupId, Location, Description, and Url attributes to replaceable parameters.

  2. Save and close the file.

Add the wizard to the VSIX package

In the source.extension.vsixmanifest file in the VSIX project, add a reference to the wizard project so that it's deployed with the VSIX package that contains the project item.

To add the wizard to the VSIX package

  1. In Solution Explorer, open the shortcut menu from the source.extension.vsixmanifest file in the CustomActionProjectItem project, and then choose Open to open the file in the manifest editor.

  2. In the manifest editor, choose the Assets tab, then choose the New button.

    The Add New Asset dialog box appears.

  3. In the Type list, choose Microsoft.VisualStudio.Assembly.

  4. In the Source list, choose A project in current solution.

  5. In the Project list, choose ItemTemplateWizard, and then choose the OK button.

  6. On the menu bar, choose Build > Build Solution, and then make sure that the solution compiles without errors.

Test the wizard

You are now ready to test the wizard. First, start to debug the CustomActionProjectItem solution in the experimental instance of Visual Studio. Then test the wizard for the Custom Action project item in a SharePoint project in the experimental instance of Visual Studio. Finally, build and run the SharePoint project to verify that the custom action works as expected.

To start to debug the solution

  1. Restart Visual Studio with administrative credentials, and then open the CustomActionProjectItem solution.

  2. In the ItemTemplateWizard project, open the CustomActionWizard code file, and then add a breakpoint to the first line of code in the RunStarted method.

  3. On the menu bar, choose Debug > Exceptions.

  4. In the Exceptions dialog box, make sure that the Thrown and User-unhandled check boxes for Common Language Runtime Exceptions are cleared, and then choose the OK button.

  5. Start debugging by choosing the F5 key, or, on the menu bar, choosing Debug > Start Debugging.

    Visual Studio installs the extension to %UserProfile%\AppData\Local\Microsoft\VisualStudio\11.0Exp\Extensions\Contoso\Custom Action Project Item\1.0 and starts an experimental instance of Visual Studio. You'll test the project item in this instance of Visual Studio.

To test the wizard in Visual Studio

  1. In the experimental instance of Visual Studio, on the menu bar, choose File > New > Project.

  2. Expand the Visual C# or Visual Basic node (depending on the language that your item template supports), expand the SharePoint node, and then choose the 2010 node.

  3. In the list of project templates, choose SharePoint 2010 Project, name the project CustomActionWizardTest, and then choose the OK button.

  4. In the SharePoint Customization Wizard, enter the URL of the site that you want to use for debugging, and then choose the Finish button.

  5. In Solution Explorer, open the shortcut menu for the project node, choose Add, and then choose New Item.

  6. In the Add New Item - CustomItemWizardTest dialog box, expand the SharePoint node, and then expand the 2010 node.

  7. In the list of project items, choose the Custom Action item, and then choose the Add button.

  8. Verify that the code in the other instance of Visual Studio stops on the breakpoint that you set earlier in the RunStarted method.

  9. Continue to debug the project by choosing the F5 key or, on the menu bar, choosing Debug > Continue.

    The SharePoint Customization Wizard appears.

  10. Under Location, choose the List Edit option button.

  11. In the Group ID list, choose Communications.

  12. In the Title box, enter SharePoint Developer Center.

  13. In the Description box, enter Opens the SharePoint Developer Center website.

  14. In the URL box, enter https://docs.microsoft.com/sharepoint/dev/, and then choose the Finish button.

    Visual Studio adds an item that's named CustomAction1 to your project and opens the Elements.xml file in the editor. Verify that Elements.xml contains the values that you specified in the wizard.

To test the custom action in SharePoint

  1. In the experimental instance of Visual Studio, choose the F5 key or, on the menu bar, choose Debug > Start Debugging.

    The custom action is packaged and deployed to the SharePoint site specified by the Site URL property of the project, and the web browser opens to the default page of this site.

    Note

    If the Script Debugging Disabled dialog box appears, choose the Yes button.

  2. In the Lists area of the SharePoint site, choose the Tasks link.

    The Tasks - All Tasks page appears.

  3. On the List Tools tab of the ribbon, choose the List tab, and then, in the Settings group, choose List Settings.

    The List Settings page appears.

  4. Under the Communications heading near the top of the page, choose the SharePoint Developer Center link, verify that the browser opens the website https://docs.microsoft.com/sharepoint/dev/, and then close the browser.

Cleaning up the development computer

After you finish testing the project item, remove the project item template from the experimental instance of Visual Studio.

To clean up the development computer

  1. In the experimental instance of Visual Studio, on the menu bar, choose Tools > Extensions and Updates.

    The Extensions and Updates dialog box opens.

  2. In the list of extensions, choose the Custom Action Project Item extension, and then choose the Uninstall button.

  3. In the dialog box that appears, choose the Yes button to confirm that you want to uninstall the extension, and then choose the Restart Now button to complete the uninstallation.

  4. Close both instances of Visual Studio (the experimental instance and the instance of Visual Studio in which the CustomActionProjectItem solution is open).

See also