Steve Apiki
CodeBlog это простое расширение VisualStudio, которое публикует фрагменты кода в Twitter и WordPress блогах, прямо из IDE. Мы бегло рассмотрим конструкцию CodeBlog, для того, что бы изучить некоторые общие правила расширений Visual Studio.
CodeBlog является небольшим расширением, которое позволит вам копировать в буфер куски кода из редактора Microsoft Visual Studio и посылать их в Twitter или свой блог. При этом для удобства задействован пункт контекстного (правый клик) меню. Шутка в чистом виде. Истинная цель - пример создания интегрированного пакета (integration package) Visual Studio, который мы можем использовать для иллюстрации пользовательской настройки среды, как-то, добавление пункта меню, перехват событий (хукинг) в редакторе и создание, и управление окном инструментов. Я построил CodeBlog используя Visual Studio 2010 Release Candidate и Visual Studio 2010 SDK RC.
Как только расширение устанавливается, CodeBlog добавляет пункт "Blog and Tweet" в контекстное меню редактора кода. Когда вы выбираете пункт меню, CodeBlog находит выделенный текст и делает следующее:
Отсылает текст в Twitter, используя Twitter API;
Отсылает текст в WordPress блог, как черновик, используя MetaWeblog API;
Добавляет визуальный эффект (называемый обрамление (adornment)) в редактор, выделяя тем самым запись с указанием соответствующего URL в блоге;
Добавляет дату, URL и текст записи в блоге в список, который может быть просмотрен позднее в окне инструментов;
Выводит черновик записи в браузер для редактирования.
Расширение устанавливает записи блога и Twitter"а в окно инструментов, которое запоминает список фрагментов кода, размещенных вами, соответственно, в блоге и Twitter"е, и создает пункт в меню View/Other Windows , который открывает это окно инструментов.
Создание пакета.
Фактически, мы используем две модели расширений Visual Studio при создании CodeBlog . CodeBlog - расширение, частично использующее как VSPackage, так и MEF (Managed Extensibility Framework). VSPackage часть CodeBlog получает доступ к UI элементам в окружении Visual Studio, таким как пункты меню и окно инструментов. MEF компонентная часть будет использоваться для добавления обрамления текста в редакторе.
SDK инсталлирует шаблон проекта Visual Studio Package, который вы можете использовать для того, что бы начать разработку VSPackage. С помощью этого шаблона, визард создания проекта позволит вам опционально включить команду меню, окно инструментов и пользовательский редактор, как часть нового проекта. Для CodeBlog мы выберем опции "команда меню" и "окно инструментов", указав имя команды ("Blog and Tweet") для команды меню, и имя окна для окна инструментов ("Blog and Tweet Entries") и ID команды для команды меню и для пункта меню, который будет вызываться в окне инструментов.
Сгенерированный с помощью шаблона проект включает файл исходного кода каркаса пакета, и несколько других файлов, которые стоит кратко упомянуть, в процессе рассмотрения структуры VSPackage. Основной файл - класс CodeBlogPackage, унаследованный от класса MPF (Managed Package Framework) Package, который реализует интерфейс IVsPackage и отвечает за обработку регистрации в среде. Так как мы запрашиваем команду меню и окно инструментов, класс пакета также включает инициализационный код для установки команд меню и метода отображения окна команд.
Класс окна инструментов наследуется от MPF ToolWindowPane и включает в себя пользовательский элемент управления WPF. Когда мы устанавливаем разметку окна Blog and Tweet Entries, мы делаем основную часть работы по настройке пользовательский элемент управления. Сгенерированный проект также включает XAML файл и Class файл для пользовательского элемента управления.
Команды пакета определены в файле таблиц команд (VSCT). VSCT файл задает расположение команд в оболочке меню, используя при этом указанные нами ID. Он предоставляет общие битмапы для каждого пункта меню, которые вы можете заменить собственными битмапами, хотя я не делал этой операции в CodeBlog. Визард размещает пункт меню вызова окна инструментов под View/Other Windows, и соответствующую команду меню в окне Инструментов. Прежде всего, нам надо перенести команду меню из окна Инструментов контекстное меню редактора, для того, что бы мы имели возможность его вызвать с помощью правой кнопки мыши.
Подключение пункта меню
Одиночная команда меню CodeBlog содержится в группе меню. В VSCTфайле описание этой группы сгенерировано следующим образом:
<Group guid="guidCodeBlogCmdSet" id="MyMenuGroup" priority="0x0600">
<Parent guid="guidSHLMainMenu" id="IDM_VS_MENU_TOOLS"/>
</Group>
Все, что нам необходимо сделать, для того, что бы перенести пункт меню "Blog and Tweet" в контекстное меню, это задать контекстный редактор окна кода в качестве родительской для группы меню, используя идентификатор IDM_VS_CTX_CODEWIN:
<Parent guid="guidSHLMainMenu" id="IDM_VS_CTXT_CODEWIN"/>
Это изменение приводит к вызову меню правой кнопкой мыши, как мы того и хотели.
Когда пункт меню нажат, мы должны посмотреть, выделен ли какой-то текст, и произвести определенное действие, если это так. Для того, что бы найти выделение, сначала нам нужно найти активное представление (View).
Как VSPackage, CodeBlog ищет активное представление в IDE, используя службы Visual Studio. Мы получаем активное представление используя службу VSTextManager.
IVsTextManager txtMgr =
(IvsTextManager)GetService(typeof(SVsTextManager));
int mustHaveFocus = 1;
txtMgr.GetActiveView(mustHaveFocus, null, out vTextView);
Как только мы получили активное представление, мы можем использовать его для получения IWPFTextView, который нам необходим для извлечения выделенного фрагмента, и последующего добавления обрамления. Техника включает несколько других вызовов, которые описаны в инструкции MSDNR. (Это руководство так же включает исходный код, многие фрагменты которого CodeBlog использует для управления обрамлением текста).
Мы получаем выделенный текст примерно так:
string selectedText = view.Selection.SelectedSpans[0].GetText();
И затем мы получаем текст, который нам необходим для Tweet"ера и поста в блоге.
Команда меню Blog and Tweet может быть использована только тогда, когда есть выделенный текст в текстовом редакторе, таким образом, имеет смысл отключить пункт меню и делать его активным только при выполнении данного условия. CodeBlog делает это, в большинстве случаев, перехватывая событие пункта меню BeforeQueryStatus и делая его (пункт меню) активным, только если текст выделен. Однако, этот метод не работает если пользователь вызывает контекстное меню до того, как CodeBlog будет загружен. В этом случае пункт меню будет активным даже без выделения (хотя указатель будет игнорировать клик).
Такое поведение на самом деле задумано в Visual Studio, которая подгружает пакет, содержащий пункты меню во время запуска, но не загружает пакет класса (который ресурсоемок) до тех пор, пока он реально не понадобится. Visual Studio предоставляет механизм декларации видимости и активного состояния для пакетов в VSCT, посредствам предопределения состояний (т.е., UICONTEXT_Debugging). CodeBlog не может использовать этот механизм потому, как активная область выделенного текста не включена в список предустановленных условий, поэтому мы имеем дело с исключением.