Arbeiten mit Katalogen

Das Windows-Menübandframework bietet Entwicklern ein robustes und konsistentes Modell für die Verwaltung dynamischer Inhalte über eine Vielzahl von sammlungsbasierten Steuerelementen hinweg. Durch Die Anpassung und Neukonfiguration der Menübandbenutzeroberfläche ermöglichen diese dynamischen Steuerelemente dem Framework, auf Benutzerinteraktionen sowohl in der Hostanwendung als auch im Menüband selbst zu reagieren, und bieten die Flexibilität, verschiedene Laufzeitumgebungen zu verarbeiten.

Einführung

Diese Fähigkeit des Menübandframeworks, sich dynamisch an Laufzeitbedingungen, Anwendungsanforderungen und Endbenutzereingaben anzupassen, unterstreicht die umfassenden Benutzeroberflächenfunktionen des Frameworks und bietet Entwicklern die Flexibilität, eine vielzahl von Kundenanforderungen zu erfüllen.

Der Schwerpunkt dieses Leitfadens besteht darin, die vom Framework unterstützten dynamischen Katalogsteuerelemente zu beschreiben, ihre Unterschiede zu erläutern, zu erörtern, wann und wo sie am besten verwendet werden können, und zu veranschaulichen, wie sie in eine Menübandanwendung integriert werden können.

Kataloge

Kataloge sind funktional und grafisch umfangreiche Listenfeldsteuerelemente. Die Elementauflistung eines Katalogs kann nach Kategorien organisiert, in flexiblen spalten- und zeilenbasierten Layouts angezeigt, mit Bildern und Text dargestellt werden und je nach Katalogtyp die Livevorschau unterstützen.

Kataloge unterscheiden sich aus den folgenden Gründen funktional von anderen dynamischen Menüband-Steuerelementen:

  • Kataloge implementieren die IUICollection-Schnittstelle , die die verschiedenen Methoden zum Bearbeiten von Katalogelementauflistungen definiert.
  • Kataloge können zur Laufzeit aktualisiert werden, basierend auf Aktivitäten, die direkt im Menüband auftreten, z. B. wenn ein Benutzer der Symbolleiste für den Schnellzugriff (QAT) einen Befehl hinzufügt.
  • Kataloge können zur Laufzeit aktualisiert werden, basierend auf Aktivitäten, die indirekt in der Laufzeitumgebung auftreten, z. B. wenn ein Druckertreiber nur Hochformatseitenlayouts unterstützt.
  • Kataloge können zur Laufzeit aktualisiert werden, basierend auf Aktivitäten, die indirekt in der Hostanwendung auftreten, z. B. wenn ein Benutzer ein Element in einem Dokument auswählt.

Das Menübandframework macht zwei Arten von Katalogen verfügbar: Elementkataloge und Befehlskataloge.

Elementkataloge

Elementkataloge enthalten eine indexbasierte Auflistung verwandter Elemente, wobei jedes Element durch ein Bild, eine Zeichenfolge oder beides dargestellt wird. Das Steuerelement ist an einen einzelnen Command-Handler gebunden, der auf dem Indexwert basiert, der durch die UI_PKEY_SelectedItem-Eigenschaft identifiziert wird.

Elementkataloge unterstützen die Livevorschau, d. h. das Anzeigen eines Befehlsergebnisses basierend auf Mouseover oder Fokus, ohne sich auf den Befehl zu verpflichten oder tatsächlich auf den Befehl zu rufen.

Wichtig

Das Framework unterstützt nicht das Hosten von Elementkatalogen im Anwendungsmenü.

 

Befehlskataloge

Befehlskataloge enthalten eine Auflistung von unterschiedlichen, nicht indizierten Elementen. Jedes Element wird durch ein einzelnes Steuerelement dargestellt, das über eine Befehls-ID an einen Befehlshandler gebunden ist. Wie eigenständige Steuerelemente leitet jedes Element in einem Befehlskatalog Eingabeereignisse an einen zugeordneten Befehlshandler weiter– der Befehlskatalog selbst lauscht nicht auf Ereignisse.

Befehlskataloge unterstützen keine Livevorschau.

Im Menübandframework gibt es vier Katalogsteuerelemente: DropDownGallery, SplitButtonGallery, InRibbonGallery und ComboBox. Alle außer comboBox können entweder als Elementkatalog oder Als Befehlskatalog implementiert werden.

Eine DropDownGallery ist eine Schaltfläche, die eine Dropdownliste anzeigt, die eine Sammlung von sich gegenseitig ausschließenden Elementen oder Befehlen enthält.

Der folgende Screenshot veranschaulicht das Menüband-Dropdownkatalog-Steuerelement in Microsoft Paint für Windows 7.

Screenshot eines Dropdown-Katalogsteuerelements in Microsoft Paint für Windows 7.

SplitButtonGallery

Ein SplitButtonGallery ist ein zusammengesetztes Steuerelement, das ein einzelnes Standardelement oder einen Befehl aus seiner Auflistung auf einer primären Schaltfläche verfügbar macht und andere Elemente oder Befehle in einer sich gegenseitig ausschließenden Dropdownliste anzeigt, die angezeigt wird, wenn auf eine sekundäre Schaltfläche geklickt wird.

Der folgende Screenshot veranschaulicht das Menüband-Steuerelement "Katalog für geteilte Schaltflächen" in Microsoft Paint für Windows 7.

Screenshot eines Katalogsteuerelements für geteilte Schaltflächen in Microsoft Paint für Windows 7.

InRibbonGallery

Eine InRibbonGallery ist ein Katalog, der eine Sammlung verwandter Elemente oder Befehle im Menüband anzeigt. Wenn zu viele Elemente im Katalog vorhanden sind, wird ein Erweiterungspfeil bereitgestellt, um den Rest der Sammlung in einem erweiterten Bereich anzuzeigen.

Der folgende Screenshot veranschaulicht das Menüband-In-Menüband-Katalog-Steuerelement in Microsoft Paint für Windows 7.

Screenshot eines In-Menüband-Katalog-Steuerelements im Microsoft Paint-Menüband.

Kombinationsfeld

Ein ComboBox-Steuerelement ist ein einspaltiges Listenfeld, das eine Auflistung von Elementen mit einem statischen Steuerelement oder einem Bearbeitungssteuerelement und Dropdownpfeil enthält. Der Listenfeldteil des Steuerelements wird angezeigt, wenn der Benutzer auf den Dropdownpfeil klickt.

Der folgende Screenshot veranschaulicht ein Menüband-Kombinationsfeld-Steuerelement aus Windows Live Movie Maker.

Screenshot eines Kombinationsfeld-Steuerelements im Microsoft Paint-Menüband.

Da comboBox ausschließlich ein Elementkatalog ist, unterstützt es keine Befehlselemente. Es ist auch das einzige Katalogsteuerelement, das keinen Befehlsbereich unterstützt. (Ein Befehlsbereich ist eine Auflistung von Befehlen, die im Markup deklariert und unten im Elementkatalog oder Befehlskatalog aufgeführt sind.)

Das folgende Codebeispiel zeigt das Markup, das zum Deklarieren eines Befehlsbereichs mit drei Schaltflächen in einer DropDownGallery erforderlich ist.

<DropDownGallery 
  CommandName="cmdSizeAndColor" 
  TextPosition="Hide" 
  Type="Commands"
  ItemHeight="32"
  ItemWidth="32">
  <DropDownGallery.MenuLayout>
    <FlowMenuLayout Rows="2" Columns="3" Gripper="None"/>
  </DropDownGallery.MenuLayout>
  <Button CommandName="cmdCommandSpace1"/>
  <Button CommandName="cmdCommandSpace2"/>
  <Button CommandName="cmdCommandSpace3"/>
</DropDownGallery>

Der folgende Screenshot veranschaulicht den Befehlsbereich mit drei Schaltflächen im vorherigen Codebeispiel.

Screenshot eines Befehlsbereichs mit drei Schaltflächen in einer Dropdownliste.

In diesem Abschnitt werden die Implementierungsdetails von Menübandkatalogen erläutert und erläutert, wie Sie sie in eine Menübandanwendung integrieren.

Grundlegende Komponenten

In diesem Abschnitt werden die Eigenschaften und Methoden beschrieben, die das Rückgrat dynamischer Inhalte im Menübandframework bilden und das Hinzufügen, Löschen, Aktualisieren und anderweitige Bearbeiten des Inhalts und des visuellen Layouts von Menübandkatalogen zur Laufzeit unterstützen.

IUICollection

Kataloge erfordern einen grundlegenden Satz von Methoden, um auf die einzelnen Elemente in ihren Sammlungen zuzugreifen und sie zu bearbeiten.

Die IEnumUnknown-Schnittstelle definiert diese Methoden, und das Framework ergänzt ihre Funktionalität durch zusätzliche Methoden, die in der IUICollection-Schnittstelle definiert sind. IUICollection wird vom Framework für jede Katalogdeklaration im Menübandmarkup implementiert.

Wenn zusätzliche Funktionen erforderlich sind, die nicht von der IUICollection-Schnittstelle bereitgestellt werden, kann ein benutzerdefiniertes Auflistungsobjekt, das von der Hostanwendung implementiert und von IEnumUnknown abgeleitet wird, durch die Frameworkauflistung ersetzt werden.

IUICollectionChangedEvent

Damit eine Anwendung auf Änderungen in einer Katalogauflistung reagiert, muss sie die IUICollectionChangedEvent-Schnittstelle implementieren. Anwendungen können Benachrichtigungen von einem IUICollection-Objekt über den Ereignislistener IUICollectionChangedEvent::OnChanged abonnieren.

Wenn die Anwendung die vom Framework bereitgestellte Katalogauflistung durch eine benutzerdefinierte Sammlung ersetzt, sollte die Anwendung die IConnectionPointContainer-Schnittstelle implementieren. Wenn IConnectionPointContainer nicht implementiert ist, kann die Anwendung das Framework nicht über Änderungen in der benutzerdefinierten Auflistung benachrichtigen, die dynamische Aktualisierungen des Katalogsteuerelements erfordern.

In den Fällen, in denen IConnectionPointContainer nicht implementiert ist, kann das Katalogsteuerelement nur durch Ungültigkeit über IUIFramework::InvalidateUICommand und IUICommandHandler::UpdateProperty oder durch Aufrufen von IUIFramework::SetUICommandProperty aktualisiert werden.

IUISimplePropertySet

Anwendungen müssen IUISimplePropertySet für jedes Element oder jeden Befehl in einer Katalogauflistung implementieren. Die Eigenschaften, die mit IUISimplePropertySet::GetValue angefordert werden können, variieren jedoch.

Elemente werden über den UI_PKEY_ItemsSource Eigenschaftenschlüssel definiert und an einen Katalog gebunden und machen Eigenschaften mit einem IUICollection-Objekt verfügbar.

Die gültigen Eigenschaften für Elemente in Elementkatalogen (UI_COMMANDTYPE_COLLECTION) werden in der folgenden Tabelle beschrieben.

Hinweis

Einige Elementeigenschaften, z . B. UI_PKEY_Label, können im Markup definiert werden. Weitere Informationen finden Sie in der Referenzdokumentation zu Eigenschaftenschlüsseln .

 

Control

Eigenschaften

ComboBox

UI_PKEY_Label, UI_PKEY_CategoryId

DropDownGallery

UI_PKEY_Label, UI_PKEY_ItemImage , UI_PKEY_CategoryId

InRibbonGallery

UI_PKEY_Label, UI_PKEY_ItemImage , UI_PKEY_CategoryId

SplitButtonGallery

UI_PKEY_Label, UI_PKEY_ItemImage, UI_PKEY_CategoryId

UI_PKEY_SelectedItem ist eine Eigenschaft des Elementkatalogs.

 

Die gültigen Elementeigenschaften für Befehlskataloge (UI_COMMANDTYPE_COMMANDCOLLECTION) werden in der folgenden Tabelle beschrieben.

Control Eigenschaften
DropDownGallery UI_PKEY_CommandId, UI_PKEY_CommandType , UI_PKEY_CategoryId
InRibbonGallery UI_PKEY_CommandId, UI_PKEY_CommandType , UI_PKEY_CategoryId
SplitButtonGallery UI_PKEY_CommandId, UI_PKEY_CommandType, UI_PKEY_CategoryId

 

Kategorien werden verwendet, um Elemente und Befehle in Katalogen zu organisieren. Kategorien werden über den UI_PKEY_Categories Eigenschaftenschlüssel definiert und an einen Katalog gebunden und machen Eigenschaften mit einem kategoriespezifischen IUICollection-Objekt verfügbar.

Kategorien verfügen nicht über einen CommandType und unterstützen keine Benutzerinteraktionen. Beispielsweise können Kategorien nicht das SelectedItem in einem Elementkatalog werden, und sie sind nicht an einen Befehl in einem Befehlskatalog gebunden. Wie andere Katalogelementeigenschaften können Kategorieeigenschaften wie UI_PKEY_Label und UI_PKEY_CategoryId durch Aufrufen von IUISimplePropertySet::GetValue abgerufen werden.

Wichtig

IUISimplePropertySet::GetValue sollte UI_COLLECTION_INVALIDINDEX zurückgeben, wenn UI_PKEY_CategoryId für ein Element angefordert wird, das keine zugeordnete Kategorie aufweist.

 

Deklarieren der Steuerelemente im Markup

Kataloge müssen wie alle Menübandsteuerelemente im Markup deklariert werden. Ein Katalog wird im Markup als Elementkatalog oder Befehlskatalog identifiziert, und es werden verschiedene Präsentationsdetails deklariert. Im Gegensatz zu anderen Steuerelementen erfordern Kataloge, dass nur das Basissteuerelement oder der Sammlungscontainer im Markup deklariert wird. Die tatsächlichen Auflistungen werden zur Laufzeit aufgefüllt. Wenn ein Katalog im Markup deklariert wird, wird das Type-Attribut verwendet, um anzugeben, ob der Katalog ein Elementkatalog eines Befehlskatalogs ist.

Für jedes der hier erläuterten Steuerelemente stehen eine Reihe optionaler Layoutattribute zur Verfügung. Diese Attribute stellen Entwicklereinstellungen für das Framework bereit, die sich direkt darauf auswirken, wie ein Steuerelement aufgefüllt und in einem Menüband angezeigt wird. Die im Markup anwendbaren Einstellungen beziehen sich auf die Anzeige- und Layoutvorlagen und verhaltensweisen, die unter Anpassen eines Menübands durch Größendefinitionen und Skalierungsrichtlinien erläutert werden.

Wenn ein bestimmtes Steuerelement Layouteinstellungen nicht direkt im Markup zulässt oder die Layouteinstellungen nicht angegeben sind, definiert das Framework steuerelementspezifische Anzeigekonventionen basierend auf dem verfügbaren Platz auf dem Bildschirm.

Die folgenden Beispiele veranschaulichen, wie Sie eine Reihe von Katalogen in ein Menüband integrieren.

Befehlsdeklarationen

Befehle sollten mit einem CommandName-Attribut deklariert werden, das verwendet wird, um dem Befehl ein Steuerelement oder eine Gruppe von Steuerelementen zuzuordnen.

Hier kann auch ein CommandId-Attribut angegeben werden, das zum Binden eines Befehls an einen Command-Handler verwendet wird, wenn das Markup kompiliert wird. Wenn keine ID angegeben wird, wird eine vom Framework generiert.

<!-- ComboBox -->
<Command Name="cmdComboBoxGroup"
         Symbol="cmdComboBoxGroup"
         Comment="ComboBox Group"
         LabelTitle="ComboBox"/>
<Command Name="cmdComboBox"
         Symbol="cmdComboBox"
         Comment="ComboBox"
         LabelTitle="ComboBox"/>

<!-- DropDownGallery -->
<Command Name="cmdDropDownGalleryGroup"
         Symbol="cmdDropDownGalleryGroup"
         Comment="DropDownGallery Group"
         LabelTitle="DropDownGallery"/>
<Command Name="cmdDropDownGallery"
         Symbol="cmdDropDownGallery"
         Comment="DropDownGallery"
         LabelTitle="DropDownGallery"/>

<!-- InRibbonGallery -->
<Command Name="cmdInRibbonGalleryGroup"
         Symbol="cmdInRibbonGalleryGroup"
         Comment="InRibbonGallery Group"
         LabelTitle="InRibbonGallery"/>
<Command Name="cmdInRibbonGallery"
         Symbol="cmdInRibbonGallery"
         Comment="InRibbonGallery"
         LabelTitle="InRibbonGallery"

<!-- SplitButtonGallery -->
<Command Name="cmdSplitButtonGalleryGroup"
         Symbol="cmdSplitButtonGalleryGroup"
         Comment="SplitButtonGallery Group"
         LabelTitle="SplitButtonGallery"/>
<Command Name="cmdSplitButtonGallery"
         Symbol="cmdSplitButtonGallery"
         Comment="SplitButtonGallery"
         LabelTitle="SplitButtonGallery"

Steuerelementdeklarationen

Dieser Abschnitt enthält Beispiele, die das grundlegende Steuerelementmarkup veranschaulichen, das für die verschiedenen Katalogtypen erforderlich ist. Sie zeigen, wie sie die Katalogsteuerelemente deklarieren und sie über das CommandName-Attribut einem Befehl zuordnen.

Das folgende Beispiel zeigt eine Steuerelementdeklaration für die DropDownGallery , bei der das Type-Attribut verwendet wird, um anzugeben, dass es sich um einen Befehlskatalog handelt.

<!-- DropDownGallery -->
<Group CommandName="cmdDropDownGalleryGroup">
  <DropDownGallery CommandName="cmdDropDownGallery"
                   TextPosition="Hide"
                   Type="Commands"
                   ItemHeight="32"
                   ItemWidth="32">
    <DropDownGallery.MenuLayout>
      <FlowMenuLayout Rows="2"
                      Columns="3"
                      Gripper="None"/>
    </DropDownGallery.MenuLayout>
    <DropDownGallery.MenuGroups>
      <MenuGroup>
        <Button CommandName="cmdButton1"></Button>
        <Button CommandName="cmdButton2"></Button>
       </MenuGroup>
       <MenuGroup>
        <Button CommandName="cmdButton3"></Button>
      </MenuGroup>
    </DropDownGallery.MenuGroups>
  </DropDownGallery>
</Group>

Das folgende Beispiel zeigt eine Steuerelementdeklaration für splitButtonGallery.

<!-- SplitButtonGallery -->
<Group CommandName="cmdSplitButtonGalleryGroup">
  <SplitButtonGallery CommandName="cmdSplitButtonGallery">
    <SplitButtonGallery.MenuLayout>
      <FlowMenuLayout Rows="2"
                      Columns="3"
                      Gripper="None"/>
    </SplitButtonGallery.MenuLayout>
    <SplitButtonGallery.MenuGroups>
      <MenuGroup>
        <Button CommandName="cmdButton1"></Button>
        <Button CommandName="cmdButton2"></Button>
      </MenuGroup>
      <MenuGroup>
        <Button CommandName="cmdButton3"></Button>
      </MenuGroup>
    </SplitButtonGallery.MenuGroups>
  </SplitButtonGallery>
</Group>

Das folgende Beispiel zeigt eine Steuerelementdeklaration für die InRibbonGallery.

Hinweis

Da inRibbonGallery eine Teilmenge ihrer Elementauflistung im Menüband angezeigt wird, ohne ein Dropdownmenü zu aktivieren, stellt sie eine Reihe optionaler Attribute bereit, die die Größe und das Elementlayout bei der Menübandinitialisierung steuern. Diese Attribute sind für die InRibbonGallery eindeutig und in den anderen dynamischen Steuerelementen nicht verfügbar.

 

<!-- InRibbonGallery -->
<Group CommandName="cmdInRibbonGalleryGroup" SizeDefinition="OneInRibbonGallery">
  <InRibbonGallery CommandName="cmdInRibbonGallery"
                   MaxColumns="10"
                   MaxColumnsMedium="5"
                   MinColumnsLarge="5"
                   MinColumnsMedium="3"
                   Type="Items">
    <InRibbonGallery.MenuLayout>
      <VerticalMenuLayout Rows="2"
                          Gripper="Vertical"/>
    </InRibbonGallery.MenuLayout>
    <InRibbonGallery.MenuGroups>
      <MenuGroup>
        <Button CommandName="cmdButton1"></Button>
        <Button CommandName="cmdButton2"></Button>
      </MenuGroup>
      <MenuGroup>
        <Button CommandName="cmdButton3"></Button>
      </MenuGroup>
    </InRibbonGallery.MenuGroups>            
  </InRibbonGallery>
</Group>

Das folgende Beispiel zeigt eine Steuerelementdeklaration für das ComboBox-Steuerelement.

<!-- ComboBox -->
<Group CommandName="cmdComboBoxGroup">
  <ComboBox CommandName="cmdComboBox">              
  </ComboBox>
</Group>

Erstellen eines Befehlshandlers

Für jeden Befehl erfordert das Menübandframework einen entsprechenden Befehlshandler in der Hostanwendung. Befehlshandler werden von der Menübandhostanwendung implementiert und von der IUICommandHandler-Schnittstelle abgeleitet.

Hinweis

Mehrere Befehle können an einen einzelnen Befehlshandler gebunden werden.

 

Ein Befehlshandler dient zwei Zwecken:

  • IUICommandHandler::UpdateProperty antwortet auf Eigenschaftenaktualisierungsanforderungen. Die Werte der Command-Eigenschaften, z. B . UI_PKEY_Enabled oder UI_PKEY_Label, werden durch Aufrufe von IUIFramework::SetUICommandProperty oder IUIFramework::InvalidateUICommand festgelegt.
  • IUICommandHandler::Execute antwortet auf Ausführungsereignisse. Diese Methode unterstützt die folgenden drei Ausführungszustände, die vom parameter UI_EXECUTIONVERB angegeben werden.
    • Der Ausführungszustand führt alle Befehle aus, an die der Handler gebunden ist, oder führt einen Commit aus.
    • Der Vorschauzustand zeigt alle Befehle in der Vorschau an, an die der Handler gebunden ist. Dadurch werden die Befehle im Wesentlichen ohne Commit für das Ergebnis ausgeführt.
    • Der CancelPreview-Zustand bricht alle Befehle in der Vorschau ab. Dies ist erforderlich, um das Durchlaufen eines Menüs oder einer Liste zu unterstützen und die Ergebnisse nach Bedarf in der Vorschau anzuzeigen und rückgängig zu machen.

Im folgenden Beispiel wird ein Katalogbefehlshandler veranschaulicht.

/*
 * GALLERY COMMAND HANDLER IMPLEMENTATION
 */
class CGalleryCommandHandler
      : public CComObjectRootEx<CComMultiThreadModel>
      , public IUICommandHandler
{
public:
  BEGIN_COM_MAP(CGalleryCommandHandler)
    COM_INTERFACE_ENTRY(IUICommandHandler)
  END_COM_MAP()

  // Gallery command handler's Execute method
  STDMETHODIMP Execute(UINT nCmdID,
                       UI_EXECUTIONVERB verb, 
                       const PROPERTYKEY* key,
                       const PROPVARIANT* ppropvarValue,
                       IUISimplePropertySet* pCommandExecutionProperties)
  {
    HRESULT hr = S_OK;
        
    // Switch on manner of execution (Execute/Preview/CancelPreview)
    switch (verb)
    {
      case UI_EXECUTIONVERB_EXECUTE:
        if(nCmdID == cmdTextSizeGallery || 
           nCmdID == cmdTextSizeGallery2 || 
           nCmdID == cmdTextSizeGallery3)
        {
          if (pCommandExecutionProperties != NULL)
          {
            CItemProperties *pItem = 
              static_cast<CItemProperties *>(pCommandExecutionProperties);
            g_prevSelection = g_index = pItem->GetIndex();
            UpdateGallerySelectedItems();
            ::InvalidateRect(g_hWindowFrame, NULL, TRUE);
          }
          else
          {
            g_prevSelection = g_index = 0;
            UpdateGallerySelectedItems();
            ::InvalidateRect(g_hWindowFrame, NULL, TRUE);
          }
        }           
        break;
      case UI_EXECUTIONVERB_PREVIEW:
        CItemProperties *pItem = 
          static_cast<CItemProperties *>(pCommandExecutionProperties);
        g_index = pItem->GetIndex();
        ::InvalidateRect(g_hWindowFrame, NULL, TRUE);
        break;
      case UI_EXECUTIONVERB_CANCELPREVIEW:
        g_index = g_prevSelection;
        ::InvalidateRect(g_hWindowFrame, NULL, TRUE);
        break;
    }   
    return hr;
  }

  // Gallery command handler's UpdateProperty method
  STDMETHODIMP UpdateProperty(UINT nCmdID,
                              REFPROPERTYKEY key,
                              const PROPVARIANT* ppropvarCurrentValue,
                              PROPVARIANT* ppropvarNewValue)
  {
    UNREFERENCED_PARAMETER(ppropvarCurrentValue);

    HRESULT hr = E_NOTIMPL;         

    if (key == UI_PKEY_ItemsSource) // Gallery items requested
    {
      if (nCmdID == cmdTextSizeGallery || 
          nCmdID == cmdTextSizeGallery2 || 
          nCmdID == cmdTextSizeGallery3)
      {
        CComQIPtr<IUICollection> spCollection(ppropvarCurrentValue->punkVal);

        int count = _countof(g_labels);

        for (int i = 0; i < count; i++)
        {
          CComObject<CItemProperties> * pItem;
          CComObject<CItemProperties>::CreateInstance(&pItem);
                    
          pItem->AddRef();
          pItem->Initialize(i);

          spCollection->Add(pItem);
        }
        return S_OK;
      }
      if (nCmdID == cmdCommandGallery1)
      {
        CComQIPtr<IUICollection> spCollection(ppropvarCurrentValue->punkVal);

        int count = 12;
        int commands[] = {cmdButton1, 
                          cmdButton2, 
                          cmdBoolean1, 
                          cmdBoolean2, 
                          cmdButton1, 
                          cmdButton2, 
                          cmdBoolean1, 
                          cmdBoolean2, 
                          cmdButton1, 
                          cmdButton2, 
                          cmdBoolean1, 
                          cmdBoolean2};

        for (int i = 0; i < count; i++)
        {
          CComObject<CItemProperties> * pItem;
          CComObject<CItemProperties>::CreateInstance(&pItem);
                    
          pItem->AddRef();
          pItem->InitializeAsCommand(commands[i]);

          spCollection->Add(pItem);
        }
        return S_OK;
      }
    }        
    else if (key == UI_PKEY_SelectedItem) // Selected item requested
    {           
      hr = UIInitPropertyFromUInt32(UI_PKEY_SelectedItem, g_index, ppropvarNewValue);           
    }
    return hr;
  }
};

Binden des Befehlshandlers

Nachdem Sie einen Befehlshandler definiert haben, muss der Befehl an den Handler gebunden werden.

Im folgenden Beispiel wird veranschaulicht, wie Sie einen Katalogbefehl an einen bestimmten Command-Handler binden. In diesem Fall sind sowohl das ComboBox - als auch das Katalogsteuerelement an die jeweiligen Command-Handler gebunden.

// Called for each Command in markup. 
// Application will return a Command handler for each Command.
STDMETHOD(OnCreateUICommand)(UINT32 nCmdID,
                             UI_COMMANDTYPE typeID,
                             IUICommandHandler** ppCommandHandler) 
{   
  // CommandType for ComboBox and galleries
  if (typeID == UI_COMMANDTYPE_COLLECTION || typeID == UI_COMMANDTYPE_COMMANDCOLLECTION) 
  {
    switch (nCmdID)
    {
      case cmdComboBox:
        CComObject<CComboBoxCommandHandler> * pComboBoxCommandHandler;
        CComObject<CComboBoxCommandHandler>::CreateInstance(&pComboBoxCommandHandler);
        return pComboBoxCommandHandler->QueryInterface(IID_PPV_ARGS(ppCommandHandler));
      default:
        CComObject<CGalleryCommandHandler> * pGalleryCommandHandler;
        CComObject<CGalleryCommandHandler>::CreateInstance(&pGalleryCommandHandler);
        return pGalleryCommandHandler->QueryInterface(IID_PPV_ARGS(ppCommandHandler));
    }
    return E_NOTIMPL; // Command is not implemented, so do not pass a handler back.
  }
}

Initialisieren einer Auflistung

Im folgenden Beispiel wird eine benutzerdefinierte Implementierung von IUISimplePropertySet für Element- und Befehlskataloge veranschaulicht.

Die CItemProperties-Klasse in diesem Beispiel wird von IUISimplePropertySet abgeleitet. Zusätzlich zur erforderlichen Methode IUISimplePropertySet::GetValue implementiert die CItemProperties-Klasse eine Reihe von Hilfsfunktionen für die Initialisierung und Indexnachverfolgung.

//
//  PURPOSE:    Implementation of IUISimplePropertySet.
//
//  COMMENTS:
//              Three gallery-specific helper functions included. 
//

class CItemProperties
  : public CComObjectRootEx<CComMultiThreadModel>
  , public IUISimplePropertySet
{
  public:

  // COM map for QueryInterface of IUISimplePropertySet.
  BEGIN_COM_MAP(CItemProperties)
    COM_INTERFACE_ENTRY(IUISimplePropertySet)
  END_COM_MAP()

  // Required method that enables property key values to be 
  // retrieved on gallery collection items.
  STDMETHOD(GetValue)(REFPROPERTYKEY key, PROPVARIANT *ppropvar)
  {
    HRESULT hr;

    // No category is associated with this item.
    if (key == UI_PKEY_CategoryId)
    {
      return UIInitiPropertyFromUInt32(UI_PKEY_CategoryId, 
                                       UI_COLLECTION_INVALIDINDEX, 
                                       pprovar);
    }

    // A Command gallery.
    // _isCommandGallery is set on initialization.
    if (_isCommandGallery)
    {           
      if(key == UI_PKEY_CommandId && _isCommandGallery)
      {
        // Return a pointer to the CommandId of the item.
        return InitPropVariantFromUInt32(_cmdID, ppropvar);
      }         
    }
    // An item gallery.
    else
    {
      if (key == UI_PKEY_Label)
      {
        // Return a pointer to the item label string.
        return UIInitPropertyFromString(UI_PKEY_Label, ppropvar);
      }
      else if(key == UI_PKEY_ItemImage)
      {
        // Return a pointer to the item image.
        return UIInitPropertyFromImage(UI_PKEY_ItemImage, ppropvar);
      }         
    }
    return E_NOTIMPL;
  }

  // Initialize an item in an item gallery collection at the specified index.
  void Initialize(int index)
  {
    _index = index;
    _cmdID = 0;
    _isCommandGallery = false;
  }

  // Initialize a Command in a Command gallery.
  void InitializeAsCommand(__in UINT cmdID)
  {
    _index = 0;
    _cmdID = cmdID;
    _isCommandGallery = true;
  }

  // Gets the index of the selected item in an item gallery.
  int GetIndex()
  {
    return _index;
  }

private:
  int _index;
  int _cmdID;
  bool _isCommandGallery;   
};

Behandeln von Sammlungsereignissen

Im folgenden Beispiel wird eine IUICollectionChangedEvent-Implementierung veranschaulicht.

class CQATChangedEvent
  : public CComObjectRootEx<CComSingleThreadModel>
  , public IUICollectionChangedEvent
{
  public:

  HRESULT FinalConstruct()
  {
    _pSite = NULL;
    return S_OK;
  }

  void Initialize(__in CQATSite* pSite)
  {
    if (pSite != NULL)
    {
      _pSite = pSite;
    }
  }

  void Uninitialize()
  {
    _pSite = NULL;
  }

  BEGIN_COM_MAP(CQATChangedEvent)
    COM_INTERFACE_ENTRY(IUICollectionChangedEvent)
  END_COM_MAP()

  // IUICollectionChangedEvent interface
  STDMETHOD(OnChanged)(UI_COLLECTIONCHANGE action, 
                       UINT32 oldIndex, 
                       IUnknown *pOldItem, 
                       UINT32 newIndex, 
                       IUnknown *pNewItem)
  {
    if (_pSite)
    {
      _pSite->OnCollectionChanged(action, oldIndex, pOldItem, newIndex, pNewItem);
    }
    return S_OK;
  }

  protected:
  virtual ~CQATChangedEvent(){}

  private:
  CQATSite* _pSite; // Weak ref to avoid circular refcounts
};

HRESULT CQATHandler::EnsureCollectionEventListener(__in IUICollection* pUICollection)
{
  // Check if listener already exists.
  if (_spQATChangedEvent)
  {
    return S_OK;
  }

  HRESULT hr = E_FAIL;

  // Create an IUICollectionChangedEvent listener.
  hr = CreateInstanceWithRefCountOne(&_spQATChangedEvent);
    
  if (SUCCEEDED(hr))
  {
    CComPtr<IUnknown> spUnknown;
    _spQATChangedEvent->QueryInterface(IID_PPV_ARGS(&spUnknown));

    // Create a connection between the collection connection point and the sink.
    AtlAdvise(pUICollection, spUnknown, __uuidof(IUICollectionChangedEvent), &_dwCookie);
    _spQATChangedEvent->Initialize(this);
  }
  return hr;
}

HRESULT CQATHandler::OnCollectionChanged(
             UI_COLLECTIONCHANGE action, 
          UINT32 oldIndex, 
             IUnknown *pOldItem, 
          UINT32 newIndex, 
          IUnknown *pNewItem)
{
    UNREFERENCED_PARAMETER(oldIndex);
    UNREFERENCED_PARAMETER(newIndex);

    switch (action)
    {
      case UI_COLLECTIONCHANGE_INSERT:
      {
        CComQIPtr<IUISimplePropertySet> spProperties(pNewItem);
                
        PROPVARIANT var;
        if (SUCCEEDED(spProperties->GetValue(UI_PKEY_CommandId, &var)))
        {
          UINT tcid;
          if (SUCCEEDED(UIPropertyToUInt32(UI_PKEY_CommandId, var, &tcid)))
          {
            FireETWEvent(tcid, L"Added to QAT");
            PropVariantClear(&var);
          }
        }
      }
      break;
      case UI_COLLECTIONCHANGE_REMOVE:
      {
        CComQIPtr<IUISimplePropertySet> spProperties(pOldItem);
                
        PROPVARIANT var;
        if (SUCCEEDED(spProperties->GetValue(UI_PKEY_CommandId, &var)))
        {
          UINT tcid;
          if (SUCCEEDED(UIPropertyToUInt32(UI_PKEY_CommandId, var, &tcid)))
          {
            FireETWEvent(tcid, L"Removed from QAT");
            PropVariantClear(&var);
          }
        }
      }
      break;
    default:
  }
  return S_OK;
}

Sammlungseigenschaften

Erstellen einer Menübandanwendung

Grundlegendes zu Befehlen und Steuerelementen

Richtlinien für die Benutzeroberfläche des Menübands

Menübandentwurfsprozess

Katalogbeispiel