Пакет Visual Studio: настройка видимости настраиваемого пункта контекстного меню Solution Explorer

Я создаю пакет Visual Studio (это мой первый раз), и моя конечная цель - создать элемент контекстного меню для исследователя решений, который работает только с определенными типами файлов. (Я думал, что это будет обычным делом, но на нем не найдены приличные учебные пособия, поэтому, если вы знаете, пожалуйста, дайте мне знать)

Я следил за простым руководством MSDN, чтобы сначала создать элемент на панели инструментов (я забыл, где это было, чтобы связать его), и это сработало нормально.

Затем я нашел способ переместить его в контекстное меню Solution Explorer. Это было достигнуто путем манипулирования файлом .vsct и имеющим такой элемент:

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

Это, вероятно, не имеет значения, но я пытаюсь установить сцену.

Теперь, поскольку я хочу показывать только элемент для определенных типов файлов, мне нужно найти способ проверить файл при нажатии правой кнопки мыши. Вырезав длинный поиск, я нашел это, и в итоге появился следующий код:

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";
}

В приведенном выше примере я просто пытаюсь установить текст, чтобы попытаться доказать, что он работает, я знаю, что есть свойство Visible, но я хочу, чтобы этот шаг работал первым. Событие BeforeQueryStatus запускается, и отладка показывает выполнение кода, как ожидалось. Однако в контекстном меню нет изменений, он остается с исходным текстом.

Что мне здесь не хватает? Почему он не обновляется?

Ответ 1

ОК, поэтому я наконец нашел решение этой проблемы, есть несколько вещей, которые вам нужно сделать...

ШАГ 1:

Нам нужно указать, что VSPackage должен "автоматически загружаться", мы делаем это так, чтобы код выполнялся при отображении ContextMenu, поскольку обычно VSPackage не инициализировался до того, как пользовательский интерфейс был показан (т.е. пункт меню был нажат). Для этого добавим атрибут класса Package, например:

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

Вы можете задаться вопросом, что это за значение GUID, ну и в этом случае он представляет константу UICONTEXT_SolutionExists, что означает, что пакет будет автоматически загружаться, когда решение будет существовать (поэтому, когда мы создаем новый или загружаем один). Я получил эту информацию здесь, так как вы могли бы сказать, что есть количество разных VSConstants, которые могут быть использованы.

Вот еще несколько ресурсов, которые перечисляют другие значения GUID, которые можно использовать:

ШАГ 2:

Теперь, когда код BeforeQueryStatus выполняется в правильном месте, все еще запутанно, почему код ничего не меняет (в моем вопросе я пытаюсь изменить Text). Ну, ответ заключается в том, что нам нужно предоставить разрешение на пакет для этого (по крайней мере, так, как я его вижу).

Для этого мы должны отредактировать файл .vsct. Внутри мы можем найти элемент Buttons, внутри которого должен быть наш ContextMenu Button. По умолчанию есть несколько комментариев, в которых упоминается использование CommandFlag node - это то, что мы хотим.

Чтобы дать разрешение нашему пакету на изменение Text, мы должны добавить следующий node:

<CommandFlag>TextChanges</CommandFlag>

Теперь, если мы запустим VSPackage, все должно работать как ожидалось!

Если вы хотите разрешить изменение Visibility элемента меню (это была моя первоначальная цель), вы можете использовать следующие CommandFlag:

<CommandFlag>DynamicVisibility</CommandFlag>

Здесь присутствует полный список флагов команд с описанием того, что они делают.

Ответ 2

Вместо прямого использования указателя, упомянутого в ответе мусефана, вы можете использовать:

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

Обратитесь к классу UIContextGuids для всех констант guid.