При загрузке и выгрузке в хост-приложении надстройка проходит через целую череду событий. Каждое из этих событий представлено методом, определенным в интерфейсе !DTExtensibility2. Эти методы описаны в табл. 13.1.
Диаграммы на рис. 13.7 и рис. 13.8 показывают, как эти методы (которые представляют собой события) укладываются в процесс нормальной загрузки и выгрузки надстройки.
Если вы вернетесь назад к коду шаблона для надстройки, то увидите, что каждый из этих методов IDTExtensibility2 реализован. Методы OnDisconnection, OnAddlnsUpdate, OnStartupComplete и OnBeginShutdown пусты; мастер реализовал только их сигнатуру. Однако метод OnConnection уже имеет порядочное количество кода (и это еще до того, как вы приложили к нему руки).
Теперь вы готовы исследовать то, что происходит в каждом из методов iDTExtensibility2.
OnAddlnsUpdate
Метод OnAddlnsUpdate вызывается тогда, когда надстройка загружается или выгружается из Visual Studio; поэтому данный метод в основном используется для обеспечения зависимостей между надстройками. Если ваша надстройка зависит от функциональности другой надстройки, то это идеальная точка для вставки той логики, которая обрабатывает такие связи.
Вот метод OnAddlnsUpdate в том виде, как он реализован мастером Add-in Wizard:
III <зшптагу>Реализует метод OnAddlnsUpdate интерфейса IDTExtensibility2.
Ill Получает уведомление тогда, когда коллекция надстроек
III изменяется.</summary>
III <param term=' custom* >Массив параметров, специфичных для III хост-приложения.</param>
III <seealso class='IDTExtensibility2' /> public void OnAddlnsUpdate(ref Array custom)
{
}
Совет
Поскольку вы не знаете, какая надстройка запустила метод OnAddlnsUpdate, то вам придется перебрать коллекцию dte. Addins и опросить свойство Connected для каждой надстройки (чтобы определить ее текущее состояние).
OnBeginShutdown
Метод OnBeginShutdown вызывается для каждой выполняющейся надстройки при завершении работы Visual Studio. Если интегрированной среде требуется какой-либо код очистки (например, сброс настроек интегрированной среды, которые были изменены в течение времени жизни надстройки), то такой код надо размещать именно в этом методе.
Пользователь может отменить процесс завершения работы Visual Studio. OnBeginShutdown произойдет независимо от того, был ли процесс завершения работы Visual Studio успешным. Поэтому вы — как разработчики надстройки — должны всегда считать, что Visual Studio закончила свою работу, и действовать соответствующим образом.
Вот метод OnBeginShutdown:
III <summary>Реализует метод OnBeginShutdown интерфейса
\
III IDTExtensibility2. Получает уведомление, что III хост-приложение выгружается.</summary>
III <param term='custom'>MaccHB параметров, специфичных для III хост-приложения.</раram>
III <seealso class='IDTExtensibility2' /> public void OnBeginShutdown(ref Array custom)
{
}
OnConnection
Метод OnConnection указывает, что надстройка загрузилась:
public void OnConnection(object application, ext_ConnectMode connectMode,
object addlnlnst, ref Array custom)
Он принимает четыре параметра. Первый параметр (application)— самый важный; он дает ссылку на объект DTE, представляющий интегрированную среду. Из главы 11 вы знаете, что объект DTE — это ключ доступа ко всей объектной модели расширяемости. Для макросов объект DTE — это глобальная переменная. Для надстроек метод OnConnection явля
ется единственным провайдером данного объекта, который таким образом обеспечивает важнейшую связь между надстройкой и ее хостом (интегрированной средой).
Второй параметр (connectMode) — это перечисление ext ConnectMode. Он точно показывает, как была загружена надстройка (список допустимых значений ext ConnectMode см. в табл. 13.2).
Параметр addlnlnst фактически является ссылкой на саму надстройку. И последний параметр (custom) — это пустой объект Array. Этот массив передается по ссылке и может использоваться для передачи параметров в надстройку и из нее.
Мастер Add-in Wizard взял первые два параметра, явно привел их к их базовым типам и присвоил их двум полям класса для последующего использования:
_applicationObject = (DTE2)application;
_addlnlnstance = (Addin)addlnlnst;
Следующий блок кода изучает значение ext ConnectMode. Если это первая загрузка надстройки (например, если ext ConnectMode равен ext cm UISetup), то код делает две вещи: создает в меню Tools пункт для надстройки и создает пользовательскую именованную команду для запуска надстройки (эта именованная команда вызывается при выборе надстройки в меню Tools).
if (connectMode == ext_ConnectMode.ext_cm_LJISetup)
{
object []contextGUIDS = new object[] { };
Commands2 commands = (Commands2)_applicationObject .Commands;
»
string toolsMenuName; try {
// Если вы хотите перенести команду в другое меню, то нужно изменить // слово "Tools" на английское название меню. Этот' код принимает культуру, // прибавляет имя меню, а затем добавляет команду в меню. Вы можете найти // список всех меню верхнего уровня в файле CommandBar.resx.
ResourceManager resourceManager = new
ResourceManager("MyFirstAddin.CommandBar",
Assembly.GetExecutingAssembly());
Culturelnfo culturelnfo = new
System.Globalization.Culturelnfo(_applicationObject.LocalelD); string resourceName = String.Concat
(culturelnfo.TwoLetterlSOLanguageName,"Tools"); toolsMenuName = resourceManager.GetString(resourceName)';
}
catch
{
//Мы пытались найти локализованную версию слова Tools, но не нашли.
//По умолчанию принимается слово en-US,
// которое, возможно, будет работать и для текущей культуры. toolsMenuName = "Tools";
}
// Поместить команду в меню Tools.
// Найти панель команд MenuBar, которая является панелью команд // верхнего уровня, содержащей все элементы главного меню:
Microsoft.VisualStudio.CommandBars.CommandBar menuBarCommandBar =
((Microsoft.VisualStudio.CommandBars.CommandBars)
_applicationObject.CommandBars)["MenuBar"];
// Найти панель команд Tools в панели команд MenuBar:
CommandBarControl toolsControl = menuBarCommandBar.Controls[toolsMenuName]; CommandBarPopup toolsPopup = (CommandBarPopup)toolsControl;
// Этот блок try/catch block можно дублировать, если вы хотите // добавить несколько команд для обработки вашей надстройкой.
// Убедитесь только, что вы также обновили метод QueryStatus/Ехес //и включили в него имена новых команд, try {
// Добавить команду в коллекцию Commands:
Command command = commands. AddNamedCommand2 (_addinlnstance,
"MyFirstAddin", "MyFirstAddin",
"Executes the command for MyFirstAddin", true, 59, ' ref contextGUIDS,
(int)vsCommandStatus.vsCommandstatusSupported +(int)vsCommandStatus.vsCommandStatusEnabled,
(int)vsCommandStyle.vsCommandStylePictAndText, vsCommandControlType.vsCommandControlTypeButton);
// Добавить элемент управления в меню Tools: if((command != null) && (toolsPopup != null))
{
*
command.AddControl(toolsPopup.CommandBar, 1);
}
}
catch(System.ArgumentException)
{
// Если мы оказались здесь, то исключение, вероятно, произошло из-за того,
// что команда с этим именем уже существует. Если это так,
// то нет необходимости повторно создавать команду,
//и мы можем спокойно игнорировать исключение.
}
Совет
Вы видите, что мастер Add-in Wizard очень щедр на комментарии. Когда вы начинаете писать собственные надстройки, очень полезно прочитать автоматически сгенерированные комментарии и просто скопировать и вставить соответствующие фрагменты кода для использования той функциональности, которую мастер уже создал для вас.