This documentation is archived and is not being maintained.

How to: Dynamically Add Menu Items using DYNAMICITEMSTART

[This topic is pre-release documentation and is subject to change in future releases. Blank topics are included as placeholders.]

A command defined in the Command Table Configuration (.Ctc) Files that is marked with the DynamicItemStart flag specifies a position in a menu where dynamically created commands are inserted. These dynamic commands are typically created when the associated VSPackage is launched. These dynamic commands can also be updated on the fly during the lifetime of the VSPackage.

Two common uses for a dynamic list are:

  1. Most Recently Used (MRU) list, typically associated the names of documents that have been recently loaded.

  2. Windows list, which typically displays the names of windows that are currently open.

The basic idea behind the DynamicItemStart flag is the command that has this flag is a placeholder. This placeholder is replaced with 0 or more commands created at runtime by the VSPackage. This means that this dynamic list cannot be populated until the VSPackage is loaded. Therefore, the menu this dynamic list appears should be invisible until the VSPackage is loaded.

To populate the dynamic list, the IDE first calls the VSPackage to get the text and status of a command starting with the command ID given to the placeholder. The IDE then increments the command ID and calls the VSPackage for the text and status of that command. The IDE continues to increment the Command ID until the VSPackage indicates there are no more dynamic items.

The first procedure describes how to create a dynamic list in a submenu to create an MRU list of items.

The second procedure describes one way to populate the dynamic list from managed code using the managed package framework (MPF).

The Walkthrough: Creating an MRU Menu List

walkthrough shows how to create an MRU list in both managed (Visual C#) and unmanaged (Visual C++) code.

To create a dynamic command list

  1. Create a new submenu and its command group as described in How to: Create Cascading Submenus.

    This submenu is going to contain the dynamic list. You should add the DefaultInvisible | DynamicVisibility to your submenu definition so the parent menu can be hidden automatically if desired.

  2. Create a command in the BUTTONS_BEGIN – BUTTONS_END section of your .ctc file. This is going to be the dynamic list placeholder.

    1. Set the Command ID field to the GUID:ID pair that represents the placeholder. This GUID:ID pair is the first in a list of dynamic commands that are later added by the VSPackage. Each subsequent dynamic command has an ID that is one greater than the previous dynamic command.

    2. Set the Group ID to the GUID:ID pair of the group that was created for the submenu in step 1.

    3. Set the Priority field to 0.

      This particular submenu contains only the single dynamic list so the priority of the first item does not matter. All subsequent dynamic items added have the same priority so the order in which they are added dictates their relative position.

    4. Set the Icon ID field to guidOfficeIcon:msotcidNoIcon.

      A dynamic command cannot have an icon associated with it so the Icon ID field must be set to indicate that no icon is to be used.

    5. Set the Button Type file to Button.

      A dynamic command is just like any other command and so has the type Button.

    6. Set the Flags field to DynamicItemStart.

      This marks the command as a placeholder.

      NoteNote

      All other flags are ignored! If you wish to control the visibility of a dynamic item, you must do so from within the VSPackage itself at runtime.

    7. Set the Button Text field to the name of the placeholder.

      Typically, this button text is not seen if the VSPackage has the opportunity to initialize the dynamic list before the menu that contains it is shown.

  3. Using the command table compiler (ctc.exe), convert your .ctc file to a binary resource that can be included in your VSPackage satellite .dll file. For information on the Command Table Compiler, see How to: Create Menu Commands for a VSPackage Using the Binary Command Table Compiler.

To implement a dynamic list in the MPF

  • The MPF uses event handlers to hide the details of the IOleCommandTarget interface and its QueryStatus method. For a VSPackage written in managed code using the MPF to support a dynamic list of menu commands, create a list of OleMenuCommand objects to represent each item in the dynamic list. Each OleMenuCommand object has the same event handlers for executing the command and for getting the status of the command. For example:

    using Microsoft.VisualStudio.Shell;
    
    //////////////////////////////////////////////////////////////////
    // Initialize the dynamic list.
    private void CreateMRUList(OleMenuCommandService mcs, int numItems)
    {
        int baseCommandID = PkCmdList.cmdidPlaceHolder;
    
        for (int i = 0; i < numItems; i++)
        {
            CommandID cmdID = new CommandID(GuidList.MyCommandSet,
                                            baseCommandID + i);
            OleMenuCommand dynamicCmd;
            dynamicCmd = new OleMenuCommand(new EventHandler(this.OnMRUExec),
                                            cmdID);
            dynamicCmd.BeforeQueryStatus += new EventHandler(this.OnMRUQueryStatus);
            mcs.AddCommand(dynamicCmd);
        }
    
        // This adds the MRU menu itself as a command so it is possible
        // to control the visibility of the menu dynamically while the
        // VSPackage is running.
        CommandID menuCmdID = new CommandID(GuidList.MyCommandSet,
                                            PkgCmdList.MyMRUMenu);
        OleMenuCommand menuCmd = new OleMenuCommand(null, menuCmdID);
        menuCmd.BeforeQueryStatus += new EventHandler(this.OnMRUMenuQueryStatus);
        mcs.AddCommand(menuCmd);
    }
    
    //////////////////////////////////////////////////////////////////
    // Handle a click on a dynamic item.
    private void OnMRUExec(object sender, EventArgs e)
    {
        OleMenuCommand menuCmd = sender as menuCmd;
        if (null != menuCmd)
        {
            int selectedID = menuCmd.CommandID.ID - PkgCmdList.cmdidPlaceHolder;
            // selectedID represents the relative index of the selected item.
        }
    }
    
    
    //////////////////////////////////////////////////////////////////
    // Handle updating the text and status of a dynamic item.
    private void OnMRUQueryStatus(object sender, EventArgs e)
    {
        OleMenuCommand menuCmd = sender as menuCmd;
        if (null != menuCmd)
        {
            int selectedID = menuCmd.CommandID.ID - PkgCmdList.cmdidPlaceHolder;
            // selectedID represents the relative index of the selected item.
            // Set menuCmd.Text to the text that is to appear for this item.
            // Set menuCmd.Visible to true or false depending on whether the item is visible.
        }
    }
    
    
    //////////////////////////////////////////////////////////////////
    // Handle updating the visibility of the MRU menu itself.
    private void OnMRUMenuQueryStatus(object sender, EventArgs e)
    {
        OleMenuCommand menuCmd = sender as menuCmd;
        if (null != menuCmd)
        {
            // Set menuCmd.Visible to true or false depending on whether
            // the MRU list should even be seen.
        }
    }
    

See Also

Show: