Question

I am creating a Visual Studio Package (this is my first time) and my end goal is to create a context-menu item for the solution explorer that only works on certain file types. (I thought this would be a common thing, but didn't find any decent tutorials on it, so if you know any please let me know)

I followed a simple MSDN guide to create an item in the toolbar first (I forget where is was to link it) and this worked fine.

Then I found a way to move it to the Solution Explorer context menu. This was achieved by manipulating the .vsct file and having an element like this:

<Parent guid="guidSHLMainMenu" id="IDM_VS_CTXT_ITEMNODE"/>

That probably doesn't matter, but I am trying to set the scene.

Now, because I want to only show the item for certain file types, I need to find a way to check the file when the right-click button is pressed. Cutting a long search short, I found this and ended up with the following code:

protected override void Initialize()
{
    //stuff
    OleMenuCommandService mcs = GetService(typeof(IMenuCommandService)) as OleMenuCommandService;
    menuItem.BeforeQueryStatus += menuItem_BeforeQueryStatus;
    //more stuff
}

void menuItem_BeforeQueryStatus(object sender, EventArgs e)
{
    var myCommand = sender as OleMenuCommand;
    myCommand.Text = "NEW NAME";
}

In the above example I am just trying to set the text to try and prove it works, I know there is a Visible property but I want this step to work first. The BeforeQueryStatus event is fired, and debugging shows the code executing as expected. However, there is no change in the context menu item, it stays with the original text.

What am I missing here? Why is it not updating?

Was it helpful?

Solution

OK, so I have finally found a solution to this problem, there are a couple of things that you need to do...

STEP 1:

We need to specify that the VSPackage should "auto-load", we do this so that the code will execute when the ContextMenu is shown, because normally the VSPackage would not initialise before the UI has been shown (i.e. the menu item has been clicked). To do this we add an attribute to the Package class, like so:

[ProvideAutoLoad("{f1536ef8-92ec-443c-9ed7-fdadf150da82}")]
public sealed class MyFirstPackage : Package

You may wonder what that GUID value is, well in this case it represents the UICONTEXT_SolutionExists constant, which means the the package will auto-load when a solution exists (so when we create a new one or load one). I got this information from here, as you might be able to tell there are a number of different VSConstants that could be used.

Here are a couple more resources that list other GUID values that can be used:

STEP 2:

Now that the BeforeQueryStatus code is executing at the correct place, it is still confusing as to why the code doesn't actually change anything (in my question I try to change the Text). Well, the answer is, because we need to give the package permission to do so (at least that's the way I see it as being).

To do this we must edit the .vsct file. Inside there we can find a Buttons element, inside which should be our ContextMenu Button. By default there are some comments which mention the use of the CommandFlag node - this is what we want.

In order to give permission for our package to change the Text we must add the following node:

<CommandFlag>TextChanges</CommandFlag>

Now, if we run the VSPackage it should all work as expected!

If you are looking to allow permission to change the Visibility of the menu item (which was my original aim) then you can use the following CommandFlag:

<CommandFlag>DynamicVisibility</CommandFlag>

There is a full list of command flags here, with descriptions on what they do.

OTHER TIPS

Instead of directly using the guid mentioned in musefan's answer, you can use:

    [ProvideAutoLoad(Microsoft.VisualStudio.Shell.Interop.UIContextGuids.SolutionExists)]

Refer to: UIContextGuids Class for all guid constants.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top