How to update contents of DynamicItemStart button inside VS package

I am doing a VS package with a DynamicItemStart button inside a menu. I have no problem loading the contents of the Dynamic button when starting VS, but I'm trying to add additional commands to its contents after some events, such as the Open project, for example. I am adding new commands to this β€œPlace Holder” button, but I cannot see the updated Visual Studio interface. I tried the UpdateUI command:

Microsoft.VisualStudio.Shell.ServiceProvider serviceProvider = new Microsoft.VisualStudio.Shell.ServiceProvider(((DTE)Microsoft.VisualStudio.Shell.ServiceProvider.GlobalProvider.GetService(typeof(DTE))) as Microsoft.VisualStudio.OLE.Interop.IServiceProvider);
IVsUIShell uiShell = serviceProvider.GetService(typeof(SVsUIShell)) as IVsUIShell;
uiShell.UpdateCommandUI(1);

I call this code on the BeforeQueryStatus Button event, but this does not work. Has anyone achieved something similar?

Any tips are really appreciated.

Edit 1: here is the code I use to add new commands

private void InitMRUMenu(ref OleMenuCommandService mcs)
{
  InitializeMRUList();
  if (_connectionsList != null)
  {
    int i = 0; 
    foreach (var conn in _connectionsList)
    {
        var cmdID = new CommandID(GuidList.guidAdvancedVSCTSampleCmdSet, this.baseMRUID + i);
        var mc = new OleMenuCommand(new EventHandler(OnMRUExec), cmdID);
        mruList.Add(conn.DisplayName);
        mc.BeforeQueryStatus += new EventHandler(OnMRUQueryStatus);
        mcs.AddCommand(mc);
        i++;
    }        
  }
}

private void OnMRUQueryStatus(object sender, EventArgs e)
{
  OleMenuCommand menuCommand = sender as OleMenuCommand;
  if (null != menuCommand)
  {
    int MRUItemIndex = menuCommand.CommandID.ID - this.baseMRUID;
    if (MRUItemIndex >= 0 && MRUItemIndex < this.mruList.Count)
    {
      menuCommand.Text = this.mruList[MRUItemIndex] as string;
    }       
  }
}

private void OnMRUExec(object sender, EventArgs e)
{
  //Do some actions
}
+3
source share
1

IOleCommandTarget.QueryStatus, - ( #):

int IOleCommandTarget.QueryStatus(ref Guid cmdGroup, uint cCmds, OLECMD[] prgCmds, IntPtr pCmdText)
{
    if (cmdGroup == yourCommandSet)
    {
        if (prgCmds[0].cmdID >= yourDynamicId && prgCmds[0].cmdID < (yourDynamicId + 16)) // suppose you want a maximum of 16 dynamic items
        {
            int index = (int)prgCmds[0].cmdID - yourDynamicId;

            OLECMDTEXT.OLECMDTEXTF flags = OLECMDTEXT.GetFlags(pCmdText);
            if (flags == OLECMDTEXT.OLECMDTEXTF.OLECMDTEXTF_NAME)
            {
                OLECMDTEXT.SetText(pCmdText, "yourText" + index);
            }

            prgCmds[0].cmdf = (uint)(OLECMDF.OLECMDF_ENABLED | OLECMDF.OLECMDF_SUPPORTED); // for example
        }
    }
}

, IOleCommandTarget.Exec , ( ).

OLECMDTEXT - , , :

/// <devdoc>
/// Helper class for setting the text parameters to OLECMDTEXT structures.
/// </devdoc>
internal static class OLECMDTEXT
{
    /// <summary>
    /// Flags for the OLE command text
    /// </summary>
    public enum OLECMDTEXTF
    {
        /// <summary>No flag</summary>
        OLECMDTEXTF_NONE = 0,
        /// <summary>The name of the command is required.</summary>
        OLECMDTEXTF_NAME = 1,
        /// <summary>A description of the status is required.</summary>
        OLECMDTEXTF_STATUS = 2
    }

    /// <summary>
    /// Gets the flags of the OLECMDTEXT structure
    /// </summary>
    /// <param name="pCmdTextInt">The structure to read.</param>
    /// <returns>The value of the flags.</returns>
    public static OLECMDTEXTF GetFlags(IntPtr pCmdTextInt)
    {
        if (pCmdTextInt == IntPtr.Zero)
            return OLECMDTEXTF.OLECMDTEXTF_NONE;

        Microsoft.VisualStudio.OLE.Interop.OLECMDTEXT pCmdText = (Microsoft.VisualStudio.OLE.Interop.OLECMDTEXT)Marshal.PtrToStructure(pCmdTextInt, typeof(Microsoft.VisualStudio.OLE.Interop.OLECMDTEXT));

        if ((pCmdText.cmdtextf & (int)OLECMDTEXTF.OLECMDTEXTF_NAME) != 0)
            return OLECMDTEXTF.OLECMDTEXTF_NAME;

        if ((pCmdText.cmdtextf & (int)OLECMDTEXTF.OLECMDTEXTF_STATUS) != 0)
            return OLECMDTEXTF.OLECMDTEXTF_STATUS;

        return OLECMDTEXTF.OLECMDTEXTF_NONE;
    }

    /// <devdoc>
    /// Accessing the text of this structure is very cumbersome.  Instead, you may
    /// use this method to access an integer pointer of the structure.
    /// Passing integer versions of this structure is needed because there is no
    /// way to tell the common language runtime that there is extra data at the end of the structure.
    /// </devdoc>
    public static string GetText(IntPtr pCmdTextInt)
    {
        Microsoft.VisualStudio.OLE.Interop.OLECMDTEXT pCmdText = (Microsoft.VisualStudio.OLE.Interop.OLECMDTEXT)Marshal.PtrToStructure(pCmdTextInt, typeof(Microsoft.VisualStudio.OLE.Interop.OLECMDTEXT));

        // Get the offset to the rgsz param.
        IntPtr offset = Marshal.OffsetOf(typeof(Microsoft.VisualStudio.OLE.Interop.OLECMDTEXT), "rgwz");

        // Punt early if there is no text in the structure.
        if (pCmdText.cwActual == 0)
            return String.Empty;

        char[] text = new char[pCmdText.cwActual - 1];
        Marshal.Copy((IntPtr)((long)pCmdTextInt + (long)offset), text, 0, text.Length);
        StringBuilder s = new StringBuilder(text.Length);
        s.Append(text);
        return s.ToString();
    }

    /// <include file='doc\NativeMethods.uex' path='docs/doc[@for="OLECMDTEXTF.SetText"]/*' />
    /// <devdoc>
    /// Accessing the text of this structure is very cumbersome.  Instead, you may
    /// use this method to access an integer pointer of the structure.
    /// Passing integer versions of this structure is needed because there is no
    /// way to tell the common language runtime that there is extra data at the end of the structure.
    /// </devdoc>
    /// <summary>
    /// Sets the text inside the structure starting from an integer pointer.
    /// </summary>
    /// <param name="pCmdTextInt">The integer pointer to the position where to set the text.</param>
    /// <param name="text">The text to set.</param>
    public static void SetText(IntPtr pCmdTextInt, string text)
    {
        Microsoft.VisualStudio.OLE.Interop.OLECMDTEXT pCmdText = (Microsoft.VisualStudio.OLE.Interop.OLECMDTEXT)Marshal.PtrToStructure(pCmdTextInt, typeof(Microsoft.VisualStudio.OLE.Interop.OLECMDTEXT));
        char[] menuText = text.ToCharArray();

        // Get the offset to the rgsz param.  This is where we will stuff our text
        IntPtr offset = Marshal.OffsetOf(typeof(Microsoft.VisualStudio.OLE.Interop.OLECMDTEXT), "rgwz");
        IntPtr offsetToCwActual = Marshal.OffsetOf(typeof(Microsoft.VisualStudio.OLE.Interop.OLECMDTEXT), "cwActual");

        // The max chars we copy is our string, or one less than the buffer size,
        // since we need a null at the end.
        int maxChars = Math.Min((int)pCmdText.cwBuf - 1, menuText.Length);

        Marshal.Copy(menuText, 0, (IntPtr)((long)pCmdTextInt + (long)offset), maxChars);

        // append a null character
        Marshal.WriteInt16((IntPtr)((long)pCmdTextInt + (long)offset + maxChars * 2), 0);

        // write out the length +1 for the null char
        Marshal.WriteInt32((IntPtr)((long)pCmdTextInt + (long)offsetToCwActual), maxChars + 1);
    }
}
+1

All Articles