Zine.net online

Witaj na Zine.net online Zaloguj się | Rejestracja | Pomoc
w Szukaj

dev2dev

Zrób to sam – SSMS addin (Menu)

 

Po serii artykułów dotyczących internals pomocnych przy tworzeniu wtyczki do SSMS przejdziemy do tego co jest najbardziej widoczne i niezbędne do jej działania: menu.

W artykule tym opiszę schemat tworzenia menu:

1. Umiejscowienie menu naszej wtyczki w menu głównym SSMS.

2. Dodanie elementu menu oraz jednego poziomu podmenu.

3. Metod resetowania menu wtyczki oraz usuwania go z menu SSMS.

 

I. Inicjacja menu.

Inicjacja menu powinna się odbyć w momencie gdy UI do SSMS jest w pełni gotowe do tego aby zaakceptować nowe elementy. Tym miejscem jest obsługa zdarzenia OnStartupComplete. Umieszczanie kodu inicjującego w metodzie OnConnect zakończy się niepowodzeniem ponieważ UI do SSMS jeszcze na tym etapie nie istnieje. Zainicjowane prawidłowo menu wtyczki pozostaje trwałym elementem UI.

image

Dla elegancji kodowania wprowadzimy kilka stałych:

#region Const

private const string VS_MENUBAR_COMMANDBAR_NAME = "MenuBar";  // nazwa obiektu menu głównego SSMS
private const string VS_TOOLS_COMMANDBAR_NAME = "Tools";  // nazwa obiektu reprezentującego element “Tools” z menu SSMS

private const string MAIN_COMMAND_NAME = "MyAddinMenu";
private const string MAIN_COMMAND_CAPTION = "My addin";
private const string MAIN_COMMAND_TOOLTIP = "My own SSMS addin tooltip";

private string REMOVE_NAME = "RemoveMyAddin";
private const string REMOVE_CAPTION = "Reset menu";
private const string REMOVE_TOOLTIP = "Reset menu tooltip";

private string UNINSTALL_NAME = "UninstallMyAddin";
private const string UNINSTALL_CAPTION = "Uninstall menu";
private const string UNINSTALL_TOOLTIP = "Uninstall menu tooltip";

private const string MAIN_CREATE_MENU_NAME = "ServiceBrokerCreate";
private const string MAIN_CREATE_MENU_CAPTION = "Create";
private const string MAIN_CREATE_MENU_TOOLTIP = "Create objects for Service Broker tooltip";

private string CREATE_MESSAGE_TYPE_NAME = "CreateMessageType";
private const string CREATE_MESSAGE_TYPE_CAPTION = "Message type";
private const string CREATE_MESSAGE_TYPE_TOOLTIP = "Crete message type for Service Broker tooltip";

private string OTHER_OPTIONS_NAME = "OtherOptions";
private const string OTHER_OPTIONS_CAPTION = "Other options";
private const string OTHER_OPTIONS_TOOLTIP = "Other options tooltip";

#endregion

Każdy element menu wtyczki ma trzy opisujące go właściwości:

- identyfikującą go nazwę,

- caption będące jego wizualną prezentacją w menu,

- tooltip pozwalający na dodatkowy opis elementu menu.

Tworząc identyfikator menu należy pamiętać aby nie zawierał kropek. W przeciwnym wypadku tworzenie menu wygeneruje wyjątek o niewiele mówiącej treści:

image

…i szukaj wiatru w polu.

Elegancko tworzony kod wymaga stosowania prawidłowej obsługi wyjątków, ale w przypadku wtyczki SSMS ma to jeszcze dodatkowe znaczenie. Wtyczka, która nie obsłuży wyjątku nie wejdzie przy ponownym starcie do metody OnConnect co może spowodować utratę części funkcjonalności lub przyczynę błędnego jej dalszego działania. W takim przypadku wtyczkę należy odinstalować i zainstalować ponownie oraz zmodyfikować kod, tak aby poprawnie obsługiwał wyjątek. Każde zagrożone potencjalnym wyjątkiem miejsce otaczamy nawiasami try-catch.

Czas odkrycie metody inicjującej menu naszej wtyczki:

 image

 

II. Tworzenie menu

 

Obiekt CommandBars jest indeksowaną kolekcją elementów menu. Instrukcja:

toolsCommandBar = commandBars[VS_TOOLS_COMMANDBAR_NAME];

odzyskuje obiekt reprezentujący menu “Tools”. Chcemy aby menu naszej wtyczki znalazło sie tuż za tym menu. Instrukcja:

int position = ((CommandBarControl)toolsCommandBar.Parent).Index + 1;

przypisuje indeks pozycji naszego menu w menu SSMS. Instrukcja:

menuCommandBar = commandBars[VS_MENUBAR_COMMANDBAR_NAME];

odzyskuje obiekt będący menu SSMS.

Nasza wtyczka ma mieć menu pod własną kontrolą niezależną od mechanizmów wtyczek do SSMS. W tym celu potrzebna jest metoda stwierdzająca, czy nasze menu jest już włączone do menu SSMS:

private bool isActive(CommandBar menuCommandBar)
{
            foreach (CommandBarControl control in menuCommandBar.Controls)
            {
                if (control.Caption == MAIN_COMMAND_CAPTION)
                    return true;
            }

            return false;
        }

Metoda ta przegląda wszystkie kontrolki podłączone do menu SSMS i sprawdza, czy caption od jakiejś kontrolki jest równy nazwie menu naszej wtyczki. Jeżeli jest to znaczy, że nasze menu jest już zainstalowane.

Przystąpimy teraz do budowania naszego menu. Metoda makeMenu przedstawia szkielet tworzenia menu zawierającego:

  • dodanie do menu bar SSMS elementu menu o identyfikatorze reprezentowanym przez stała MAIN_COMMAND_NAME, mającego caption reprezentowane przez stałą MAIN_COMMAND_CAPTION oraz tooltip reprezentowane przez stałą MAIN_COMMAND_TOOLTIP i występującego na pozycji określonej przez parametr position (powyżej określiliśmy, że będzie to pozycja tuż za elementem “Tools” w menu SSMS), ten element menu jest reprezentowany prze obiekt MainSbMenu,
  • dodanie do elementu głównego naszego menu dwóch menu rozwijanych (reprezentowanych przez obiekty CreateMenu oraz ToolWindowsMenu)
  • do obiektu CreateMenu zostanie dodany jeden element popup menu reprezentowany przez obiekt CreateMenuPopup,
  • do obiektu ToolWindowsMenu zostaną dodane dwa obiekty będące również elementami popup menu realizującymi dwa polecenia realizowane przez SSMS (zresetowanie menu wtyczki oraz usunięcie menu wtyczki).

 

image 

image

Jak widać z powyższego kodu, tworzenie elementów menu czy będących pniami dla gałęzi menu czy liści menu zawierającymi named commands to obie metody CreatemainMenu oraz CreateSubMenu mają taką samą charakterystykę parametrów:

  • parent – jest nadrzędnym obiektem menu, do którego dodawany jest element tworzonego menu,
  • name – jest identyfikatorem tworzonego menu,
  • caption – jest wizualną reprezentacją tworzonego menu,
  • group – true oznacza, że bieżący element tworzonego menu będzie otwierał grupę menu oddzieloną separatorem, false oznacza, że separtor menu nie będzie występował,
  • position – oznacza pozycję na liście menu dodawanej do nadrzędnego menu. Stąd w przypadku dodawania do ToolWindowsMenu kolejne pozycje dodawanych do niego elementów menu są indeksowane poprzez ToolMenuPopup.Controls.Count + 1.

Metoda CreateMainMenu nie tworzy wykonywalnego named command  dla SSMS a jedynie pień dla gałęzi menu. Metoda ta jest prosta i nie wymaga szerszego wyjaśniania.

image

Metoda CreateSubMenu ma jedno miejsce, które wymaga szczególnego wyjaśnienia.

image

Ten kod to

try
{
        command = applicationObject.Commands.Item(addInInstance.ProgID + "." + name, -1);
}
catch
{
}

Kod ten jest próbą pobrania obiektu naszego menu. Jeżeli menu to nie istnieje to generowany jest wyjątek (chociaż lepiej byłoby gdyby zamiast tego zwracał po prostu null). Jeżeli wystąpi wyjątek to zmienna command będzie miała wartość null  i znaczyć to będzie, że takiego elementu menu nie ma w SSMS i należy utworzyć go oraz powiązane z nim named command. Warto zwrócić uwagę na dwa szczególne fakty:

  • tworzony named command  ma ustawione vsCommandStatusSupported  oraz          vsCommandStatusEnabled czyniąc tym samym pozwolenie na jego wykonanie.
  • tworząc element menu nadajemy mu identyfikator określony parametrem name ale SSMS zabezpiecza się przed możliwością zdublowania takich samych poleceń z różnych wtyczek lub pokrycia się ich z poleceniami SSMS i wobec tego nasze polecenie widziane jest przez SSMS jako:

addInInstance.ProgID + "." + name

gdzie addInInstance.ProgID to nic innego jak konstrukcja <namespace>.<class> co w przypadku naszej wtyczki i menu odinstalowania wtyczki oznacza, że SSMS pełny identyfikator dla tego menu będzie następujący: NextAddin.Connect.UninstallMyAddin. Konstrukcja ta być może jest również wyjaśnieniem dlaczego dodanie kropki w podawanej przez nas nazwie menu powoduje wyjątek. Być może SSMS przeszukuje ostatniej kropki w pełnym identyfikatorze menu i wszystko co jest na lewo od kropki traktowane jest jako <namespace>.<class>, których SSMS w tym wypadku nie jest w stanie zlokalizować.

A tak wygląda menu naszej wtyczki dodane do SSMS:

image

III. Resetowanie i odinstalowanie menu wtyczki

Rozwijając wtyczkę będziemy stawać przed problemem jak zmodyfikować menu naszej wtyczki. Należałoby zbudować metodę, która usunie wszystkie command rozpoczynające się od konstrukcji addInInstance.ProgID oraz element główny naszego menu z SSMS. Zastosowanie tej metody wraz z metodą inicjacji menu dawałoby nam efekt zresetowania menu a tym samym ujawnienia nowych oraz usunięcia starych opcji. Odinstalowanie menu wtyczki wymagałoby wywołania jedynie metody usuwania. Odinstalowanie menu powinno się wykonywać przed odinstalowaniem wtyczki, w przeciwnym wypadku elementy menu pozostaną w SSMS i próby ich wywołania będą się kończyć komunikatem błędu. Resetowanie wtyczek, które jest możliwe w Visual Studio z poziomu linii poleceń uruchamiających go nie jest możliwe w przypadku SSMS (nie ma takiej opcji w linii poleceń SSMS).

Metoda odinstalowania wygląda następująco:

image

Metoda resetowania wygląda następująco:

image

Jak spowodować aby metody ResetMyAddin i UninstallAddin wykonały się z menu naszej wtyczki będzie przedmiotem następnego odcinka serii (Exec).

Linki:

do poprzedniego odcinka serii o tworzeniu wtyczki do SSMS

do następnego odcinka serii o tworzeniu wtyczki do SSMS

Opublikowane 18 października 2009 22:10 przez marekpow

Komentarze:

 

dotnetomaniak.pl said:

Dziękujemy za publikację - Trackback z dotnetomaniak.pl

października 18, 2009 23:19
Komentarze anonimowe wyłączone
W oparciu o Community Server (Personal Edition), Telligent Systems