Gastposting von Oliver Scheer, Developer Evangelist - Windows, Silverlight und UI-Technologien bei der Microsoft Deutschland GmbH.

24_0Nur noch 24 Tage bis zum Windows 7 Launch.

Heute befassen wir uns mit einem alten Bekannten: der Multifunktionsleiste. Die Multifunktionsleiste wurde neu in Windows 7 integriert und entspricht nahezu der Multifunktionsleiste von Office 2007. Nahezu bedeutet dabei, dass sie konsequent weiterentwickelt wurde.

Windows 7 und die Multifunktionsleiste

Die Multifunktionsleiste ist in einige Klassiker eingeflossen: Paint und WordPad. Schade ist, dass sie es nicht auch in Notepad geschafft hat.

image

image

Die Multifunktionsleiste ist ebenso in Windows Live Movie Maker integriert worden. Dieser läuft auch unter Windows Vista und zeigt, dass die Multifunktionsleiste auch auf Vista verfügbar sein wird.

Entwickeln mit der Multifunktionsleiste

Windows 7 führt ein neues natives API für Multifunktionsleisten-basierte Oberflächen ein. Dieses API ist COM-basiert. Das API wird in Zukunft auch für Windows Vista verfügbar sein und nahezu den gleichen Funktionsumfang wie die Office 2007-Multifunktionsleiste haben.

Um als Entwickler die Multifunktionsleiste verwenden zu können, benötigt man das Windows 7 SDK (Link). Im SDK finden Sie unter anderem die Header-Datei (UIRibbon.h), die den Zugriff auf die Multifunktionsleiste bietet.

Die Programmierung der Multifunktionsleiste teilt sich in zwei Bereiche auf: Im Deklarationsteil werden die verschiedenen Elemente, wie z.B. Tabreiter, Gruppierungen oder Kommandos, deklariert und ihr Aussehen beschrieben. Diese Beschreibung kann mit XAML (Extensible Markup Language) geschrieben werden. Die Ausführung der Kommandos und das Wechseln in verschiedene Zustände wird über C++-Code beschrieben, der die Darstellung mit der Anwendungslogik verknüpft, der eigentlichen Anwendungslogik.

image

Dadurch erhält man eine starke Separation in Model, Sicht und Controller, die den Code und das Markup entkoppelt. Die gesamte C++-API dazu ist sehr kompakt gehalten. Sie ist auf Kommandos fokussiert und nicht auf Steuerelemente oder Darstellungsdetails.

Welche Steuerelemente bringt die Multifunktionsleiste mit

Die Multifunktionsleiste verfügt über ein sehr großes Repertoire an Steuerelementen, die wir bereits aus Paint, WordPad und dem Windows Live Movie Maker her kennen.

image

Eine Funktion die nicht direkt in der Multifunktionsleiste integriert ist, sondern an beliebigen Stellen in der Anwendung verwendet werden kann, ist das erweiterte Kontextmenü. In WordPad erscheint dies leicht transparent, wenn man einen Text markiert. Darüber kann man dann zum Beispiel den selektierten Text formatieren. Diese Funktion erspart dem Benutzer, größere Strecken mit der Maus zurückzulegen und somit seinen aktuellen Fokus (den Text) zu verlassen.

image

image

image

image

image

image

image

image

image

image

image

image

image

image

image

Markup der Multifunktionsleiste

Der Markup-Code für die Multifunktionsleiste unterteilt sich in zwei Bereiche: Command-Sektion und Views-Sektion.

Die Command-Sektion beinhaltet die einzelnen Command-Elemente: einen Referenznamen, ein Label, eine eindeutige ID, ein Bild (BMP) und einen Tooltip.

<?xmlversion="1.0" encoding="utf-8"?>
<Applicationxmlns=’http://schemas.microsoft.com/windows/2009/Scenic/Intent’>
<Application.Commands>
<CommandName=’Home’ LabelTitle=’Home’/>
<CommandName=’HomePage’ LabelTitle=’HomePage’>
<Command.LargeImages>
<ImageSource=’res/HomePageHH.bmp’/>
</Command.LargeImages>
</Command>
</Application.Commands>

Die Views-Sektion legt die Organisation der Kommandos in Tabs, Gruppen, Quick Access-Toolbar und Anwendungsmenü fest. Sie bestimmt außerdem, welches Steuerelement für welches Kommando verantwortlich ist.

<Application.Views>
<Ribbon>
<Ribbon.Tabs>
<Tab CommandName=’Home’>
<Group CommandName=’GoHomePage’ SizeDefinition=’OneButton’>
<Button CommandName=’HomePage’/>
</Group>
</Tab>
</Ribbon.Tabs>
</Ribbon>
</Application.Views>
</Application>

Die Multifunktionsleiste unterstützt zwei Arten von “Sichten”: die Multifunktionsleisten-Sicht und die kontextuelle UI-Sicht. Die kontextuelle UI-Sicht bietet ein reicheres Kontextsystem als bisherige Kontextmenüs.

Da es sich bei der Multifunktionsleiste um eine native API handelt, muss aus der XAML-Datei erst einmal eine native Ressource erstellt werden. Dies geschieht mit einem Tool aus dem Windows SDK: UICC.exe. Dieses generiert aus der XAML-Datei eine Ressource, die man wiederum in seine Anwendung einbinden kann und dadurch die Multifunktionsleiste als nativen Code vorliegen hat.

UICC.exe konvertiert XAML in ein binäroptimiertes Format und erstellt eine .rc-Datei, welche den binären “blob” mit den verwendeten Ressourcen enthält. Man sollte einen benutzerdefinierten Build-Step für die Erstellung der .rc-Datei mittels UICC.exe in sein Projekt einbauen, damit dieses automatisch während des Erstellens geschieht. Eine .h-Datei, die die #defines für die diversen Command-IDs enthält, wird ebenfalls generiert.

Anwendungsmodi

Durch Anwendugsmodi lässt sich die Darstellung von Elementen an den aktuellen Anwendungszustand koppeln, denn nicht immer soll alles sichtbar sein. In Microsoft Paint wird z.B. der Text-Tab nur angezeigt wenn man Text bearbeitet. Ansonsten wird diese Funktion nicht benötigt. Im Markup-Code definiert man die Anwendungsmodi, in denen die Elemente sichtbar sein sollen. Der Anwendungsmodus wird auf untergeordnete Steuerelemente automatisch vererbt.

<Button CommandName=’Paste’ ApplicationModes=’1,3′/>

Im Code kann man den Modus durch die Funktion IUIFrameworkSetModes ändern.

Die API-Interfaces im Überblick

  • IUIFramework – initialisiert Multifunktionsleiste, lädt Markup-Resourcen, Get und Set für Command-Eigenschaften oder State, Set Application Modes.
  • IUIApplication–Ermittelt User Command-Handler für jedes Command, welches im Markup definiert wurde. Benachrichtigt über View-State-Änderungen.
  • IUICommandHandler –Behandelt Commands und Property-Updates (z.B. Aktivieren und Deaktivieren eines Commands, basierend auf der aktuellen Sicht) .

Codebeispiel: Initialisierung

IUIFramework* g_pFramework = NULL;
::CoCreateInstance(CLSID_UIMultifunktionsleisteFramework, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&g_pFramework));
CComObject<CApplication> *pApp = NULL;
CComObject<CApplication>::CreateInstance(&pApp);
CComPtr<IUIApplication> spApp(pApp);
g_pFramework->Initialize(hWindowFrame, spApp);
g_pFramework->LoadUI(GetModuleHandle(NULL), L"APPLICATION_Multifunktionsleiste");

Codebeispiel: Behandeln von Ereignissen

class CApplication :
public CComObjectRootEx<CComMultiThreadModel>,
public IUIApplication,
public IUICommandHandler
{
public:
BEGIN_COM_MAP(CApplication)
COM_INTERFACE_ENTRY(IUIApplication)
COM_INTERFACE_ENTRY(IUICommandHandler)
END_COM_MAP()

STDMETHOD(OnSichtChanged)(UINT32 nSichtID,
__in UI_SichtTYPE typeID, __in IUnknown* pSicht,
UI_SichtVERB verb, INT32 uReasonCode)
{ return E_NOTIMPL; }
STDMETHOD(OnCreateUICommand)(UINT32 nCmdID,
__in UI_COMMANDTYPE typeID,
__deref_outIUICommandHandler** ppCmdHndlr)
{ return QueryInterface(IID_PPV_ARGS(ppCmdHndlr)); }
STDMETHOD(OnDestroyUICommand)(UINT32 commandId,
__in UI_COMMANDTYPE typeID,
__in_optIUICommandHandler* pCommandHandler)
{ return E_NOTIMPL; }
STDMETHODIMP Execute(UINT nCmdID,
UI_EXECUTIONVERB verb,
__in_opt const PROPERTYKEY* key,
__in_opt const PROPVARIANT* ppropvarValue,
__in_optIUISimplePropertySet* pCmdExecProps)
{
if (verb == UI_EXECUTIONVERB_EXECUTE
&& nCmdID == HomePage)
MessageBox(NULL, L"Clicked on HomePagebtn”, L"HomePage Button Execute“, MB_OK);
return S_OK;
}
STDMETHODIMP UpdateProperty(UINT nCmdID,
__in REFPROPERTYKEY key,
__in_opt const PROPVARIANT* ppropvarCurrentValue,
__out PROPVARIANT* ppropvarNewValue)
{
if (key == UI_PKEY_Enabled &&
nCmdID == HomePage && m_bPressed)
{
return UIInitPropertyFromBoolean(
UI_PKEY_Enabled, FALSE, ppropvarNewValue);
}
return E_NOTIMPL;
}

Ein vollständiges Beispiel befindet sich im Windows 7 SDK (Link).