How-To Create a Snap-in That Uses MMCListView

 

Applies To: Windows 10, Windows 7, Windows 8, Windows 8.1, Windows Server 2008, Windows Server 2008 R2, Windows Server 2012, Windows Server 2012 R2, Windows Server Technical Preview, Windows Vista

The MMC list view shows a list of result nodes in the results pane. This is the most commonly used view that is particularly suited to snap-ins that are designed to manage a dynamic list of items. The MMC list view supports small icons, large icons, lists, and report views. It also supports multi-select and single select operations on items, and a multiple column view with the ability to sort by column.

The MMC list view supports the following different modes for displaying result nodes in the results pane:

  1. List: Items are displayed as title strings to the right of their small (16x16) icon representations. Sub-items and column headers are not displayed.

  2. Large Icon: Items are displayed as title strings below their large (32x32) icon representations. Sub-items and column headers are not displayed.

  3. Small Icon: Items are displayed as title strings below their small (16x16) icon representations. Sub-items and column headers are not displayed.

  4. Report: Items are displayed as title strings to the right of their small (16x16) icon representations and placed under the first column header on the left side of the results pane. Subsequent column headers are arranged from left to right and corresponding sub-items are placed beneath each main item.

A list view is a quick way to add the following functionality to a snap-in:

  • Insert, delete, and modify columns.

  • Insert, delete, enumerate, and modify result items.

  • Create view modes (report view, list view, icon view, and small icon view) and switch between them.

  • Configure list view capabilities, behaviors, and visual styles.

This sample demonstrates how to create a snap-in that uses an MMC list view. It automatically inherits the capability to add or remove columns and sort columns, which is a functionality that is built into an MMC list view.

Create the snap-in (file SelectionListviewSnapIn.cs)

  1. Similar to the snap-in created in How-To Create a Hello World Snap-in, create a class called SelectionListviewSnapIn and add the following attributes.

    using System;
    using System.ComponentModel;
    using System.Security.Permissions;
    using Microsoft.ManagementConsole;
    
    [assembly: PermissionSetAttribute(SecurityAction.RequestMinimum, Unrestricted = true)]
    namespace Microsoft.ManagementConsole.Samples
    {
        /// <summary>
        /// Allows the .Net framework to install the assembly.
        /// </summary>
        [RunInstaller(true)]
        public class InstallUtilSupport : SnapInInstaller
        {
        }
        /// <summary>
        /// Provides the main entry point for the creation of a snap-in.
        /// </summary>
        [SnapInSettings("{CE255EF6-9E3D-42c8-B725-95CCC761B9D9}",
           DisplayName = "- Selection (MmcListView) Sample", 
            Description = "Shows MmcListView with multi-selection.")]
        public class SelectionListviewSnapIn : SnapIn
        {
            /// <summary>
            /// Constructor.
            /// </summary>
            public SelectionListviewSnapIn()
            {
    
    
        ...
    
                }
        }
    
    }//namespace
    
  2. Create a root node. To show an MMC list view in the results pane, a scope node must add a list view description to its view descriptions collection. The type of the list view description is the type of the class that is derived from MMC list view. In the next part, we will create a list view class called SelectionListView. For now, we will assign its type to the view type of the list view description. This assignment lets MMC create the correct view type when the scope node is selected and the results pane needs to get populated. The list view options field is set to ExcludeScopeNodes. Setting this option causes the scope nodes to be excluded from the list view. By default, when this option is not set, any child of the selected scope node that is itself a scope node is shown in the list view. Since MMC is a multi-document interface (MDI) application, for any given scope node there may be multiple results pane instances at a given time. MMC manages the view instances. The developer of a snap-in is responsible for advertising the types of views that are available for a scope node using the ViewDescriptions property. Add the newly created list view description to the collection and set its index to zero.

    public class SelectionListviewSnapIn : SnapIn
    {
        /// <summary>
        /// Constructor.
        /// </summary>
        public SelectionListviewSnapIn()
        {
            // Create the root node.
            this.RootNode = new ScopeNode();
            this.RootNode.DisplayName = "Selection (MmcListView) Sample";
    
            // Create a message view for the root node.
            MmcListViewDescription lvd = new MmcListViewDescription();
            lvd.DisplayName = "Users (MmcListView)";
            lvd.ViewType = typeof(SelectionListView);
            lvd.Options = MmcListViewOptions.ExcludeScopeNodes;
    
            // Attach the view to the root node.
            this.RootNode.ViewDescriptions.Add(lvd);
            this.RootNode.ViewDescriptions.DefaultIndex = 0;
            this.RootNode.Children.Add(new ScopeNode());
            this.RootNode.Children.Add(new ScopeNode());
            this.RootNode.Children.Add(new ScopeNode());
            this.RootNode.Children.Add(new ScopeNode());
        }
    }
    
  3. Here is the complete code for the selection list view snap-in.

    using System;
    using System.ComponentModel;
    using System.Security.Permissions;
    using Microsoft.ManagementConsole;
    
    [assembly: PermissionSetAttribute(SecurityAction.RequestMinimum, Unrestricted = true)]
    namespace Microsoft.ManagementConsole.Samples
    {
        /// <summary>
        /// Allows the .Net framework to install the assembly.
        /// </summary>
        [RunInstaller(true)]
        public class InstallUtilSupport : SnapInInstaller
        {
        }
        /// <summary>
        /// Provides the main entry point for the creation of a snap-in.
        /// </summary>
        [SnapInSettings("{CE255EF6-9E3D-42c8-B725-95CCC761B9D9}",
           DisplayName = "- Selection (MmcListView) Sample", 
            Description = "Shows MmcListView with multi-selection.")]
        public class SelectionListviewSnapIn : SnapIn
        {
            /// <summary>
            /// Constructor.
            /// </summary>
            public SelectionListviewSnapIn()
            {
                // Create the root node.
                this.RootNode = new ScopeNode();
                this.RootNode.DisplayName = "Selection (MmcListView) Sample";
    
                // Create a message view for the root node.
                MmcListViewDescription lvd = new MmcListViewDescription();
                lvd.DisplayName = "Users (MmcListView)";
                lvd.ViewType = typeof(SelectionListView);
                lvd.Options = MmcListViewOptions.ExcludeScopeNodes;
    
                // Attach the view to the root node.
                this.RootNode.ViewDescriptions.Add(lvd);
                this.RootNode.ViewDescriptions.DefaultIndex = 0;
                this.RootNode.Children.Add(new ScopeNode());
                this.RootNode.Children.Add(new ScopeNode());
                this.RootNode.Children.Add(new ScopeNode());
                this.RootNode.Children.Add(new ScopeNode());
            }
        }
    
    }//namespace
    

Create the list view( file SelectionListView.cs)

  1. Create a list view class called SelectionListView that inherits from MmcListView and add a default constructor.

    using System;
    //using System.Collections.Generic;
    using System.Windows.Forms;
    using System.Text;
    
    namespace Microsoft.ManagementConsole.Samples
    {
        /// <summary>
        /// This class provides list of icons and names in the results pane.
        /// </summary>
        public class SelectionListView : MmcListView
        {
            /// <summary>
            /// Constructor.
            /// </summary>
            public SelectionListView()
            {
            }
    
    
        ...
    
            } // class
    } //namespace
    
  2. Code three functions in this view, starting with OnInitialize. The OnInitialize function overrides OnInitialize to perform custom initialization for the list view. It sets the width of column zero and gives it a title. It also adds one detail column.

    /// <summary>
    /// Defines the structure of the list view.
    /// </summary>
    /// <param name="status"></param>
    protected override void OnInitialize(AsyncStatus status)
    {
        // do default handling
        base.OnInitialize(status);
    
        // Create a set of columns for use in the list view
        // Define the default column title
        this.Columns[0].Title = "User";
        this.Columns[0].SetWidth(300);
    
        // Add detail column
        this.Columns.Add(new MmcListViewColumn("Birthday", 200));
    
        // Set to show all columns
        this.Mode = MmcListViewMode.Report;  // default (set for clarity)
    
        // Set to show refresh as an option
        this.SelectionData.EnabledStandardVerbs = StandardVerbs.Refresh;
    
        // Load the list with values
        Refresh();
    }
    
  3. Next, define what happens when a selection is changed. If there are no selected nodes, then this method simply clears the selection data; otherwise, it populates the selection data. It also adds a new action that shows the selected items to the actions pane.

    /// <summary>
    /// Defines actions for selection.
    /// </summary>
    /// <param name="status"></param>
    protected override void OnSelectionChanged(SyncStatus status)
    {
        if (this.SelectedNodes.Count == 0)
        {
            this.SelectionData.Clear();
        }
        else
        {
            this.SelectionData.Update(GetSelectedUsers(), this.SelectedNodes.Count > 1, null, null);
            this.SelectionData.ActionsPaneItems.Clear();
            this.SelectionData.ActionsPaneItems.Add(new Action("Show Selected", "Shows list of selected Users.", -1, "ShowSelected"));
        }
    }
    
  4. OnSelectionsAction defines what happens when an action is selected. Here, we have only one action and we invoke the ShowSelected method when it is selected.

    /// <summary>
    /// Handles menu actions.
    /// </summary>
    /// <param name="action"></param>
    /// <param name="status"></param>
    protected override void  OnSelectionAction(Action action, AsyncStatus status)
    {
        switch ((string)action.Tag)
        {
            case "ShowSelected":
                {
                    ShowSelected();
                    break;
                }
        }
    }
    
  5. OnRefresh defines what happens on refresh. This is a placeholder and is not implemented yet in this sample.

    /// <summary>
    /// Placeholder.
    /// </summary>
    /// <param name="status"></param>
    protected override void OnRefresh(AsyncStatus status)
    {
        MessageBox.Show("The method or operation is not implemented.");
    }
    
  6. Provide an implementation of the ShowSelected method. For this sample, it simply pops up a message box that shows the selected users.

    /// <summary>
    /// Shows selected items.
    /// </summary>
    private void ShowSelected()
    {
        MessageBox.Show("Selected Users: \n" + GetSelectedUsers());
    }
    
  7. GetSelectedUsers specifies how the selected users are rendered.

    /// <summary>
    /// Builds a string of selected users.
    /// </summary>
    /// <returns></returns>
    private string GetSelectedUsers()
    {
        StringBuilder selectedUsers = new StringBuilder();
    
        foreach (ResultNode resultNode in this.SelectedNodes)
        {
    
            selectedUsers.Append(resultNode.DisplayName + "\n");
        }
    
        return selectedUsers.ToString();
    }
    
  8. Here is an implementation of the Refresh method that decides what happens when the view is refreshed. For the purpose of this sample, define a fictitious list of users and display it on Refresh.

    /// <summary>
    /// Loads the list view with data.
    /// </summary>
    public void Refresh()
    {
        // Clear existing information.
        this.ResultNodes.Clear();
    
        // Use fictitious data to populate the lists.
        string[][] users = { new string[] {"Karen", "February 14th"},
                                    new string[] {"Sue", "May 5th"},
                                    new string[] {"Tina", "April 15th"},
                                    new string[] {"Lisa", "March 27th"},
                                    new string[] {"Tom", "December 25th"},
                                    new string[] {"John", "January 1st"},
                                    new string[] {"Harry", "October 31st"},
                                    new string[] {"Bob", "July 4th"}
                                };
    
        // Populate the list.
        foreach (string[] user in users)
        {
            ResultNode node = new ResultNode();
            node.DisplayName = user[0];
            node.SubItemDisplayNames.Add(user[1]);
    
            this.ResultNodes.Add(node);
        }
    }
    
  9. Here is the complete code for the selection list view.

    using System;
    //using System.Collections.Generic;
    using System.Windows.Forms;
    using System.Text;
    
    namespace Microsoft.ManagementConsole.Samples
    {
        /// <summary>
        /// This class provides list of icons and names in the results pane.
        /// </summary>
        public class SelectionListView : MmcListView
        {
            /// <summary>
            /// Constructor.
            /// </summary>
            public SelectionListView()
            {
            }
            /// <summary>
            /// Defines the structure of the list view.
            /// </summary>
            /// <param name="status"></param>
            protected override void OnInitialize(AsyncStatus status)
            {
                // do default handling
                base.OnInitialize(status);
    
                // Create a set of columns for use in the list view
                // Define the default column title
                this.Columns[0].Title = "User";
                this.Columns[0].SetWidth(300);
    
                // Add detail column
                this.Columns.Add(new MmcListViewColumn("Birthday", 200));
    
                // Set to show all columns
                this.Mode = MmcListViewMode.Report;  // default (set for clarity)
    
                // Set to show refresh as an option
                this.SelectionData.EnabledStandardVerbs = StandardVerbs.Refresh;
    
                // Load the list with values
                Refresh();
            }
            /// <summary>
            /// Defines actions for selection.
            /// </summary>
            /// <param name="status"></param>
            protected override void OnSelectionChanged(SyncStatus status)
            {
                if (this.SelectedNodes.Count == 0)
                {
                    this.SelectionData.Clear();
                }
                else
                {
                    this.SelectionData.Update(GetSelectedUsers(), this.SelectedNodes.Count > 1, null, null);
                    this.SelectionData.ActionsPaneItems.Clear();
                    this.SelectionData.ActionsPaneItems.Add(new Action("Show Selected", "Shows list of selected Users.", -1, "ShowSelected"));
                }
            }
    
            /// <summary>
            /// Placeholder.
            /// </summary>
            /// <param name="status"></param>
            protected override void OnRefresh(AsyncStatus status)
            {
                MessageBox.Show("The method or operation is not implemented.");
            }
            /// <summary>
            /// Handles menu actions.
            /// </summary>
            /// <param name="action"></param>
            /// <param name="status"></param>
            protected override void  OnSelectionAction(Action action, AsyncStatus status)
            {
                switch ((string)action.Tag)
                {
                    case "ShowSelected":
                        {
                            ShowSelected();
                            break;
                        }
                }
            }
            /// <summary>
            /// Shows selected items.
            /// </summary>
            private void ShowSelected()
            {
                MessageBox.Show("Selected Users: \n" + GetSelectedUsers());
            }
    
            /// <summary>
            /// Builds a string of selected users.
            /// </summary>
            /// <returns></returns>
            private string GetSelectedUsers()
            {
                StringBuilder selectedUsers = new StringBuilder();
    
                foreach (ResultNode resultNode in this.SelectedNodes)
                {
    
                    selectedUsers.Append(resultNode.DisplayName + "\n");
                }
    
                return selectedUsers.ToString();
            }
            /// <summary>
            /// Loads the list view with data.
            /// </summary>
            public void Refresh()
            {
                // Clear existing information.
                this.ResultNodes.Clear();
    
                // Use fictitious data to populate the lists.
                string[][] users = { new string[] {"Karen", "February 14th"},
                                            new string[] {"Sue", "May 5th"},
                                            new string[] {"Tina", "April 15th"},
                                            new string[] {"Lisa", "March 27th"},
                                            new string[] {"Tom", "December 25th"},
                                            new string[] {"John", "January 1st"},
                                            new string[] {"Harry", "October 31st"},
                                            new string[] {"Bob", "July 4th"}
                                        };
    
                // Populate the list.
                foreach (string[] user in users)
                {
                    ResultNode node = new ResultNode();
                    node.DisplayName = user[0];
                    node.SubItemDisplayNames.Add(user[1]);
    
                    this.ResultNodes.Add(node);
                }
            }
        } // class
    } //namespace
    

Steps to create, install, and run the snap-in

  1. To install this snap-in, run the .NET Framework InstallUtil.exe program using the following command-line command: InstallUtil.exe SelectionListViewSample.dll. Note that if the Microsoft.ManagementConsole dll is not in the GAC, both the Microsoft.ManagementConsole.dll and the SelectionListViewSample.dll must be in the same directory. If you need to uninstall the snap-in later, run the previous InstallUtil.exe command with the /uninstall switch.

  2. The InstallUtil.exe command attempts to install your snap-in using the SnapInSettingsAttribute. The utility creates a file called InstallUtil.InstallLog to show the success or failure of the install and all the actions that were taken.

  3. InstallUtil.exe populates the registry entries for the given snap-in under the HKLM/Software/Microsoft/MMC/SnapIns key.

  4. After the snap-in is installed, the snap-in is visible to MMC and can be added to the MMC Console using the Add/Remove Dialog. To test this snap-in, run MMC 3.0 (mmc.exe) and use the Add/Remove Snap-in menu. The Selection(MMCLIstView) Sample displays in the dialog and can be loaded in the MMC console.

See Also

Microsoft.ManagementConsole
MMC Technology Summary