How to: Extend a SharePoint node in Server Explorer

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

You can extend nodes under the SharePoint Connections node in Server Explorer. This is useful when you want to add new child nodes, shortcut menu items, or properties to an existing node. For more information, see Extend the SharePoint connections node in Server Explorer.

To extend a SharePoint node in Server Explorer

  1. Create a class library project.

  2. Add references to the following assemblies:

    • Microsoft.VisualStudio.SharePoint

    • Microsoft.VisualStudio.SharePoint.Explorer.Extensions

    • System.ComponentModel.Composition

  3. Create a class that implements the IExplorerNodeTypeExtension interface.

  4. Add the ExportAttribute attribute to the class. This attribute enables Visual Studio to discover and load your IExplorerNodeTypeExtension implementation. Pass the IExplorerNodeTypeExtension type to the attribute constructor.

  5. Add the ExplorerNodeTypeAttribute attribute to the class. This attribute specifies the string identifier for the type of node that you want to extend.

    To specify built-in node types provided by Visual Studio, pass one of the following enumeration values to the attribute constructor:

    • ExplorerNodeTypes: Use these values to specify site connection nodes (the nodes that display site URLs), site nodes, or all other parent nodes in Server Explorer.

    • ExtensionNodeTypes: Use these values to specify one of the built-in nodes that represent an individual component on a SharePoint site, such as a node that represents a list, field, or content type.

  6. In your implementation of the Initialize method, use members of the nodeType parameter to add features to the node. This parameter is an IExplorerNodeType object that provides access to the events defined in the IExplorerNodeEvents interface. For example, you can handle the following events:

Example

The following code example demonstrates how to create two different types of node extensions:

  • An extension that adds a context menu item to SharePoint site nodes. When you click the menu item, it displays the name of the node that was clicked.

  • An extension that adds a custom property named ContosoExampleProperty to each node that represents a field named Body.

    using System.ComponentModel;
    using System.ComponentModel.Composition;
    using System.Windows.Forms;
    using Microsoft.VisualStudio.SharePoint;
    using Microsoft.VisualStudio.SharePoint.Explorer;
    using Microsoft.VisualStudio.SharePoint.Explorer.Extensions;
    
    namespace Contoso.ServerExplorerExtension
    {
        [Export(typeof(IExplorerNodeTypeExtension))]
        [ExplorerNodeType(ExplorerNodeTypes.SiteNode)]
        internal class SiteNodeExtensionWithContextMenu : IExplorerNodeTypeExtension
        {
            public void Initialize(IExplorerNodeType nodeType)
            {
                nodeType.NodeMenuItemsRequested += nodeType_NodeMenuItemsRequested;
            }
    
            void nodeType_NodeMenuItemsRequested(object sender, ExplorerNodeMenuItemsRequestedEventArgs e)
            {
                IMenuItem menuItem = e.MenuItems.Add("Display Message");
                menuItem.Click += menuItem_Click;
            }
    
            void menuItem_Click(object sender, MenuItemEventArgs e)
            {
                IExplorerNode node = (IExplorerNode)e.Owner;
                MessageBox.Show(string.Format("Clicked the menu item for the '{0}' node.", node.Text));
            }
        }
    
        [Export(typeof(IExplorerNodeTypeExtension))]
        [ExplorerNodeType(ExtensionNodeTypes.FieldNode)]
        internal class FieldNodeExtensionWithProperty : IExplorerNodeTypeExtension
        {
            public void Initialize(IExplorerNodeType nodeType)
            {
                nodeType.NodePropertiesRequested += nodeType_NodePropertiesRequested;
            }
    
            void nodeType_NodePropertiesRequested(object sender, ExplorerNodePropertiesRequestedEventArgs e)
            {
                // Only add the property to "Body" fields.
                if (e.Node.Text == "Body")
                {
                    ExampleProperty propertyObject;
    
                    // If the properties object already exists for this node, get it from the node's annotations.
                    if (!e.Node.Annotations.TryGetValue(out propertyObject))
                    {
                        // Otherwise, create a new properties object and add it to the annotations.
                        propertyObject = new ExampleProperty(e.Node);
                        e.Node.Annotations.Add(propertyObject);
                    }
    
                    e.PropertySources.Add(propertyObject);
                }
            }
        }
    
        internal class ExampleProperty
        {
            private IExplorerNode node;
            private const string propertyId = "Contoso.ExampleProperty";
            private const string propertyDefaultValue = "This is an example property.";
    
            internal ExampleProperty(IExplorerNode node)
            {
                this.node = node;
            }
    
            // Gets or sets a simple string property. 
            [DisplayName("ContosoExampleProperty")]
            [DescriptionAttribute("This is an example property for field nodes.")]
            [DefaultValue(propertyDefaultValue)]
            public string TestProperty
            {
                get
                {
                    string propertyValue;
    
                    // Get the current property value if it already exists; otherwise, return a default value.
                    if (!node.Annotations.TryGetValue(propertyId, out propertyValue))
                    {
                        propertyValue = propertyDefaultValue;
                    }
                    return propertyValue;
                }
                set
                {
                    if (value != propertyDefaultValue)
                    {
                        // Store the property value in the Annotations property of the node. 
                        // Data in the Annotations property does not persist when Visual Studio exits.
                        node.Annotations[propertyId] = value;
                    }
                    else
                    {
                        // Do not save the default value.
                        node.Annotations.Remove(propertyId);
                    }
                }
            }
        }
    
    }
    
    Imports System.ComponentModel
    Imports System.ComponentModel.Composition
    Imports System.Windows.Forms
    Imports Microsoft.VisualStudio.SharePoint
    Imports Microsoft.VisualStudio.SharePoint.Explorer
    Imports Microsoft.VisualStudio.SharePoint.Explorer.Extensions
    
    Namespace Contoso.ServerExplorerExtension
        <Export(GetType(IExplorerNodeTypeExtension))> _
        <ExplorerNodeType(ExplorerNodeTypes.SiteNode)> _
        Friend Class SiteNodeExtensionWithContextMenu
            Implements IExplorerNodeTypeExtension
    
            Private Sub Initialize(ByVal nodeType As IExplorerNodeType) _
                Implements IExplorerNodeTypeExtension.Initialize
                AddHandler nodeType.NodeMenuItemsRequested, AddressOf NodeMenuItemsRequested
            End Sub
    
            Private Sub NodeMenuItemsRequested(ByVal Sender As Object, ByVal e As ExplorerNodeMenuItemsRequestedEventArgs)
                Dim menuItem = e.MenuItems.Add("Display Message")
                AddHandler menuItem.Click, AddressOf MenuItemClick
            End Sub
    
            Private Sub MenuItemClick(ByVal Sender As Object, ByVal e As MenuItemEventArgs)
                Dim node As IExplorerNode = CType(e.Owner, IExplorerNode)
                MessageBox.Show(String.Format("Clicked the menu item for the '{0}' node.", node.Text))
            End Sub
        End Class
    
        <Export(GetType(IExplorerNodeTypeExtension))> _
        <ExplorerNodeType(ExtensionNodeTypes.FieldNode)> _
        Friend Class FieldNodeExtensionWithProperty
            Implements IExplorerNodeTypeExtension
    
            Private Sub Initialize(ByVal nodeType As IExplorerNodeType) _
                Implements IExplorerNodeTypeExtension.Initialize
                AddHandler nodeType.NodePropertiesRequested, AddressOf NodePropertiesRequested
            End Sub
    
            Private Sub NodePropertiesRequested(ByVal Sender As Object, ByVal e As ExplorerNodePropertiesRequestedEventArgs)
                Dim propertyObject As ExampleProperty = Nothing
    
                ' Only add the property to "Body" fields.
                If e.Node.Text = "Body" Then
                    ' If the properties object already exists for this node, get it from the node's annotations.
                    If False = e.Node.Annotations.TryGetValue(propertyObject) Then
                        ' Otherwise, create a new properties object and add it to the annotations.
                        propertyObject = New ExampleProperty(e.Node)
                        e.Node.Annotations.Add(propertyObject)
                    End If
                    e.PropertySources.Add(propertyObject)
                End If
            End Sub
        End Class
    
        Friend Class ExampleProperty
    
            Private node As IExplorerNode
            Private Const propertyId As String = "Contoso.CustomActionTestProperty"
            Private Const propertyDefaultValue As String = "This is a test value."
    
            Friend Sub New(ByVal node As IExplorerNode)
                Me.node = node
            End Sub
    
            ' Gets or sets a simple string property. 
            <DisplayName("ContosoExampleProperty")> _
            <DescriptionAttribute("This is an example property for field nodes.")> _
            <DefaultValue(propertyDefaultValue)> _
            Public Property TestProperty As String
                Get
                    Dim propertyValue As String = Nothing
    
                    ' Get the current property value if it already exists; otherwise, return a default value.
                    If False = node.Annotations.TryGetValue(propertyId, propertyValue) Then
                        propertyValue = propertyDefaultValue
                    End If
                    Return propertyValue
                End Get
                Set(ByVal value As String)
                    If value <> propertyDefaultValue Then
                        ' Store the property value in the Annotations property of the node. 
                        ' Data in the Annotations property does not persist when Visual Studio exits.
                        node.Annotations(propertyId) = value
                    Else
                        ' Do not save the default value.
                        node.Annotations.Values.Remove(propertyId)
                    End If
                End Set
            End Property
        End Class
    End Namespace
    

    This extension adds an editable string property to nodes. You can also create custom properties that display read-only data from the SharePoint server. For an example that demonstrates how to do this, see Walkthrough: Extend Server Explorer to display web parts.

Compile the code

This example requires references to the following assemblies:

  • Microsoft.VisualStudio.SharePoint

  • Microsoft.VisualStudio.SharePoint.Explorer.Extensions

  • System.ComponentModel.Composition

  • System.Windows.Forms

Deploy the extension

To deploy the Server Explorer extension, create a Visual Studio extension (VSIX) package for the assembly and any other files that you want to distribute with the extension. For more information, see Deploy extensions for the SharePoint tools in Visual Studio.

See also