Механизм регистрации страницы Options такой же, как и для надстройки: используется addin-файл. При помощи добавления нескольких строк кода XML вы можете указать Visual
Studio, что в пользовательской надстройке существует страница Options. Вы можете сделать это посредством редактирования addin-файла прямо в Visual Studio (поскольку он автоматически создается как часть проекта).
Для включения необходимой регистрационной информации в виде XML отредактируйте addin- файл и поместите в него следующий XML-код (перед закрывающим тегом </extensibility>):
<ToolsOptionsPage>
<Category Name="Color Palette">
<SubCategory Name="Code Generation">
<Assembly>C:\Users\lpowers\My Documents\Visual Studio 2008\Projects\ PaletteControlAddIn\PaletteControlAddIn\bin\PaletteControlAddIn.dll</Assembly> <FullClassName>PaletteControlAddIn.PaletteControlOptionPage </FullClassName> </SubCategory>
</Category>
</ToolsOptionsPage>
Для указания названия категории опций (отображаемой в диалоговом окне Tools Options) нужно использовать тег Category. Тег SubCategory указывает подузел под этой категорией. Тег Assembly дает путь к dll-файлу надстройки, а тег FullClassName содержит полное имя класса надстройки.
Теперь надстройка полностью работоспособна. Вы можете откомпилировать проект и затем немедленно загрузить надстройку при помощи менеджера Add-in Manager. На рис. 13.13 доказана надстройка в действии, а полный код для классов Connect, PaletteControl и PaletteControlOptionPage (именно в таком порядке) приведен в листингах 13.2—13.4. Полный исходный код этой надстройки можно скачать с сайта SAMS (informit.com/sams).
using System; using Extensibility; using EnvDTE; using EnvDTE80;
using Microsoft.VisualStudio.CommandBars;
using System.Resources;
using System.Reflection;
using System.Globalization;
using System.Windows. Forms;
namespace ColorSelectorAddln
III <summary>06beKT для реализации надстройки.</summary> III <seealso class=lIDTExtensibility2' />
public class Connect’: IDTExtensibility2, IDTCommandTarget {
#region Fields
private DTE2 _applicationObject; private Addin _addlnlnstance; private PaletteControl _paletteControl;
#endregion
III <summary>Реализует конструктор для объекта надстройки.
Ill Разместите ваш инициализационный код в этом методе. </summary> public Connect()
#region Events and Event Handlers
private void paletteControll_ColorSelected(object sender, EventArgs e) {
try
TextDocument currDoc =
(TextDocument)_applicationObject.ActiveDocument.Object(""); EditPoint2 ep = (EditPoint2)
currDoc.Selection.ActivePoint.CreateEditPoint();
ер.Insert(_paletteControl.Code); ep.InsertNewLine(1);
}
catch (Exception ex)
{
MessageBox.Show("Exception caught: " + ex.ToString());
}
}
#endregion
III <summary>Peami3yeT метод OnConnection интерфейса IDTExtensibility2. Ill Получает уведомление о том, что надстройка III загружается.</summary>
III <param term='application'Жорневой объект хост-приложения.
///</param>
III <param term='connectMode'>Описывает, как загружается III надстройкам/рагаш>
III <param tern^'addlnlnst'>Объект, представляющий эту III надстройку.</param>
III <seealso class='IDTExtensibility2' />
public void OnConnection(object application, ext_ConnectMode connectMode,
abject addlnlnst, ref Array custom)
{
_applicationObject = (DTE2)application;
_addlnlnstance = (Addin)addlnlnst;
if (connectMode == ext_ConnectMode.ext_cm_UISetup) •
{
object []contextGUIDS = new object[] { };
Commands2 commands = (Commands2)_applicationObject.Commands; string toolsMenuName;
try
{
string resourceName;
ResourceManager resourceManager =
new ResourceManager("ColorSelectorAddln.CommandBar",
Assembly.GetExecutingAssembly()) ;
new Culturelnfo(_applicationObject.LocalelD); if (culturelnfo.TwoLetterlSOLanguageName == "zh")
{
System.Globalization.Culturelnfo parentCulturelnfo =
culturelnfo.Parent; resourceName = String.Concat(parentCulturelnfo.Name, "Tools");
}
else
{
resourceName =
String.Concat(culturelnfo.TwoLetterlSOLanguageName,"Tools");
}
toolsMenuName = resourceManager.GetString(resourceName);
}
catch
{
//Мы пытались отыскать локализованную версию слова Tools,
// но не нашли. По умолчанию принимаем слово en-LJS word,
// которое, возможно, будет работать для текущей культуры. 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/Exec //и включить названия новых команд, try {
// Добавить команду в коллекцию Commands:
Command command = commands. AddNamedCommand2 (_addlnlnstance, "ColorSelectorAddln", "ColorSelectorAddln",
"Executes the command for ColorSelectorAddln", 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) ,
{
// Если мы попали сюда, то, вероятно, исключение произошло потому, // что команда с таким именем уже существует. Если это так, то // нет необходимости повторно создавать команду, и мы можем просто // игнорировать исключение.
}
}
#region Create Tool Window // Коллекция DTE.ToolWindows
Windows2 windows = (Windows2)_applicationObject.Windows;
// Объект указателя места заполнения; в конечном итоге ссылается // на пользовательский элемент управления, находящийся // в пользовательском элементе управления, object paletteObject = null;
// Этот раздел указывает путь и имя класса для элемента управления // "палитра", который будет находиться в новом окне инструмента;
// нам нужно также указать его заголовок и уникальный GUID.
Window toolWindow;
Assembly asm = System.Reflection.Assembly.GetExecutingAssembly() ; string assemblyPath = asm.Location;
string className = "ColorSelectorAddln.PaletteControl"; string guid = "{62175059-FD7E-407a-9EF3-5D07F2B704E8}"; string caption = "Color Selector";
try
{
// Создать новое окно инструмента и вставить в него
// пользовательский элемент управления.
toolWindow = windows.CreateToolWindow2(_addlnlnstance,
assemblyPath, className, caption, guid, ref paletteObject);
// Если окно инструмента было создано успешно, сделать его видимым if (_toolWindow != null)
{
_toolWindow.Visible = true;
}
// Получить ссылку на объект пользовательского элемента управления jpaletteControl = (PaletteControl)paletteObject;
// Подключить обработчик события PaletteControl.ColorSelected jpaletteControl.ColorSelected +=
new System.EventHandler (palet.teControll_ColorSelected) ;
}
catch (Exception ex)
{
MessageBox.Show("Exception caught: " + ex.ToString());
}
#endregion
ъ
}
III <зигптагу>Реализует метод OnDisconnection интерфейса III IDTExtensibility2. Получает уведомление, что III надстройка выгружается.</summaгy>
III <param term='disconnectMode'>Описывает, как надстройка III выгружается.</param>
III <param term-'custom'>Массив специфичных для III хост-приложения параметров.</param>
III <seealso class='IDTExtensibility2' />
public void OnDisconnection(ext_DisconnectMode disconnectMode,
ref Array custom)
III <summary>Реализует метод OnAddlnsUpdate интерфейса III IDTExtensibility2. Получает уведомление, когда III изменяется коллекция надстроек.</summary>
III <param term='custom'>Массив специфичных для III хост-приложения параметров.</param>
III <seealso class=lIDTExtensibility2' /> public void OnAddlnsUpdate(ref Array custom)
{
}
III <зиттагу>Реализует метод OnStartupComplete интерфейса
III IDTExtensibility2. Получает уведомление, что хост-приложение
III загрузку закончило.</summary>
III <param term='custom'>Массив специфичных для III хост-приложения параметров.</param>
/// <seealso class='IDTExtensibility2' /> public void OnStartupComplete(ref Array custom)
{
}
III <зиттагу>Реализует метод OnBeginShutdown интерфейса IDTExtensibility2. Ill Получает уведомление, что хост-приложение выгружается.</summary>
III <param term='custom'>Массив специфичных для III хост-приложения параметров.</param>
III <seealso class='IDTExtensibility2' /> public void OnBeginShutdown(ref Array custom)
{
}
/// <summary>Реализует метод QueryStatus интерфейса IDTCommandTarget.
Ill Вызывается тогда, когда обновляется доступность команды</зиттагу>
III <param term=' commandName' >Название команды, состояние III которой надо определить.</param>
III <param term='neededText'>Текст, который необходим для команды.</param> III <param term='status'>Состояние команды в пользовательском III интерфейсе.</param>
III <param term='commandText'>Текст, необходимый для /// параметра neededText.</param>
III <seealso class='Exec' />
public void QueryStatus(string commandName,
vsCommandStatusTextWanted neededText, ref vsCommandStatus status, ref object commandText)
if(neededText == vsCommandStatusTextWanted.vsCommandStatusTextWantedNone) {
if(commandName == "ColorSelectorAddln.Connect.ColorSelectorAddln")
{
status = (vsCommandStatus)
vsCommandStatus.vsCommandStatusSupported IvsCommandStatus.vsCommandStatusEnabled;
return;
}
}
/// <summary>Реализует метод Exec интерфейса IDTCommandTarget.
Ill Вызывается при запуске команды.</summary>
/// <param term='commandName' >Имя команды, которую надо III выполнить.</param>
III <param term='executeOption'>Описывает, как команда III должна выполняться.</param>
III <param term='varln'>Параметры, передаваемые от вызывающей стороны III обработчику команды. </param>
III <param term^'varOut'>Параметры, передаваемые от обработчика команды III вызывающей стороне.</param>
III <param term='handled'>Информирует вызывающую сторону о том,
III была ли команда обработана.</param>
III <seealso class='Exec' />
public void Exec(string commandName, vsCommandExecOption executeOption, ref object varln, ref object varOut, ref bool handled)
{
handled = false;
if (executeOption == vsCommandExecOption.vsCommandExecOptionDoDefault) {
if (commandName == "ColorSelectorAddln.Connect.ColorSelectorAddln")
{
handled = true; return;
}
}
}
}
}
using Systembusing System.Collections.Generic; using System.ComponentModel; using System.Drawing; using System.Data;
using System.Runtime.InteropServices; using .System.Text; using System.Windows.Forms; using Microsoft.Win32;
namespace ColorSelectorAddln
[Guid("62175059-FD7E-407a-9EF3-5D07F2B704E8")] public partial class PaletteControl : UserControl {
#region Fields
string _code = "";
bool _generateVB = false;
#endregion
#region Properties public string Code {
get { return _code; }
}
public bool GenerateVB {
get { return _generateVB; }
}
#endregion #region Ctor(s)
public PaletteControl() InitializeComponent();
this.pictureBoxPalette.MouseMove += new
MouseEventHandler(pictureBoxPalette_MouseMove); this.pictureBoxPalette.Cursor = System.Windows.Forms.Cursors.Cross;
}
#endregion
#region Event Handlers and Delegates
void pictureBoxPalette_MouseMove(object sender, MouseEventArgs e)
{
11 Получить цвет под текущим положением указателя мыши
Color color = GetPointColor(е.Х, e.Y);
/
II Обновить метки RGB и второе поле изображения // при помощи полученного цвета DisplayColor(color) ;
If Сгенерировать наш код (на языке VB или С#) для структуры Color SetCode(color, _generateVB);
>
public event EventHandler ColorSelected; protected virtual void OnColorSelected(EventArgs e)
{
if (ColorSelected != null)
ColorSelected(this, e);
}
private void pictureBoxPalette_Click(object sender, EventArgs e)
{
OnColorSelected(new EventArgs());
}
#endregion
#region Private Routines III <summary>
III Возвращает структуру Color, представляющую цвет пиксела III в указанных координатах х и у.
Ill </summary>
III <param name="xM></param>
III <param name=My"></param>
III <returns>CTpyKTypa Color</returns> private Color GetPointColor(int x, int y)
{
// Получить растровое изображение из поля изображения палитры Bitmap bmp = (Bitmap)pictureBoxPalette..Image;
// Использовать GetPixel для получения цветовой структуры // для текущего положения указателя Color color = bmp.GetPixel(х, у);
// Вернуть цветовую структуру . return color;
}
III <summary>
/// Отображает значения RGB для заданного цвета. Также настраивает /// цвет фона второго поля изображения.</summary>
/// <param пате="со1огм>Цвет для отображения</рагат> private void DisplayColor(Color color)
{
// Извлечь значения RGB из цветовой структуры string R = color.R.ToString(); string G = color.G.ToString() ; string В = color.В.ToString() ;
11 Настроить наше второе поле изображения на показ текущего цвета this.pictureBoxColor.BackColor = color;
II Показать значения RGB в метках this.labelRValue.Text = R; this.labelGValue.Text = G; this.labelBValue.Text = B;
}
III <summary>
III Генерирует строку, представляющую код на языке C# или VB,
III необходимый для создания структуры Color, которая соответствует /// переданной внутрь структуре Color. Эта строка затем присваивается
III полю _code данного пользовательского элемента управления.
Ill </summary>
III <param пате="со1огм>Цвет для представления в коде.</param>
III <param name=MisVB">ByneB флаг, указывающий используемый язык:
III false означает язык С#, a true означает VB</param> private void SetCode(Color color, bool isVB)
{
// Прочитать настройки надстройки из реестра SetPropFromReg();
string code = ; if (isVB)
{
code = "Dim color As Color = ";
}
else
{
code = "Color color = ";
}
code = code + "Color.FromArgb(" + color.R.ToString() + ", " + color.G.ToString() + ", " + color.B.ToString() + ");";
_code = code;
this.labelCode.Text = _code;
}
III <summary>
III Читает элемент реестра и настраивает соответствующим образом
III выходные поля языка.
Ill </summary>
private void SetPropFromReg()
{
try
{
RegistryKey regKey =
Registry.CurrentUser.OpenSubKey(@"Software\Contoso\Addins\ColorPalette"); string codeVal = (string)regKey.GetValue("Language", "CSharp");
if (codeVal == "CSharp")
{
_generateVB = false;
}
else
{
generateVB = true;
}
}
catch (Exception ex)
{
// Ошибка чтения из реестра; принимаем по умолчанию язык C# _generateVB = false;
}
}
#endregion
}
}
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System. Drawing;
using System.Data;
using System.Text;
using System.Windows.Forms;
using EnvDTE;
using Microsoft.Win32;
namespace ColorSelectorAddln
public partial class PaletteControloptionPage : UserControl,
IDTToolsOptionsPage
{
public PaletteControloptionPage()
{
InitializeComponent();
}
#region IDTToolsOptionsPage Members
public void GetProperties(ref object PropertiesObject)
{
throw new NotlmplementedException();
}
public void OnAfterCreated(DTE DTEObject)
{
// Читаем наше текущее значение из регистра.
// Учтите: здесь следовало бы добавить код на случай непредвиденных // обстоятельств — для создания ключа реестра в случае его // отсутствия, обработки непредвиденных значений, исключений и т. д.
RegistryKey regKey = Registry.CurrentUser.OpenSubKey _
(@"Software\Contoso\Addins\ColorPaletteM); string codeVal = (string)regKey.GetValue("Language", "CSharp");
if (codeVal == "CSharp")
{
this.radioButtonCSharp.Checked = true; this.radioButtonVB.Checked = false;
}
else
{
this.radioButtonCSharp.Checked = true; this.radioButtonVB.Checked = false;
}
public void OnCancelO {
throw new NotlmplementedException();
}
public void OnHelpO {
throw new NotlmplementedException();
}
public void OnOK()
{
string codeValue = "CSharp"; // значение по умолчанию if (this.radioButtonVB.Checked)
{
codeValue = "VB";
}
// Обновить регистр новой настройкой
RegistryKey regKey = Registry.CurrentUser.OpenSubKey _
(@"Software\Contoso\Addins\ColorPalette");
Примечание
Если у вас есть надстройки, которые были написаны для предыдущей версии Visual Studio, то вам понадобится произвести некоторые изменения в их исходном коде (для полной миграции их функциональных возможностей в Visual Studio 2008). Подробно шаги такой миграции описаны в документации MSDN по Visual Studio. Ищите статью "How to: Update Visual Studio 2005 Add-ins to Visual Studio 2008".