Compartir a través de


Trabajar con galerías

El marco de la cinta de opciones de Windows proporciona a los desarrolladores un modelo sólido y coherente para administrar contenido dinámico en una variedad de controles basados en colecciones. Al adaptar y volver a configurar la interfaz de usuario de la cinta de opciones, estos controles dinámicos permiten al marco responder a la interacción del usuario tanto en la aplicación host como en la propia cinta de opciones, y proporcionan la flexibilidad para controlar varios entornos de tiempo de ejecución.

Introducción

Esta capacidad del marco de la cinta de opciones para adaptarse dinámicamente a las condiciones en tiempo de ejecución, los requisitos de la aplicación y la entrada del usuario final resalta las funcionalidades de interfaz de usuario enriquecidas del marco y proporciona a los desarrolladores la flexibilidad necesaria para satisfacer una amplia gama de necesidades de los clientes.

El enfoque de esta guía es describir los controles dinámicos de la galería compatibles con el marco de trabajo, explicar sus diferencias, analizar cuándo y dónde se pueden usar mejor y demostrar cómo se pueden incorporar en una aplicación de cinta de opciones.

Galerías

Las galerías son controles de cuadro de lista funcionales y gráficomente enriquecidos. La colección de elementos de una galería se puede organizar por categorías, que se muestran en diseños flexibles basados en columnas y filas, representados con imágenes y texto, y según el tipo de galería, admitan la vista previa en vivo.

Las galerías son funcionalmente distintas de otros controles dinámicos de la cinta de opciones por los siguientes motivos:

  • Las galerías implementan la interfaz IUICollection que define los distintos métodos para manipular colecciones de elementos de la galería.
  • Las galerías se pueden actualizar en tiempo de ejecución, en función de la actividad que se produce directamente en la cinta de opciones, como cuando un usuario agrega un comando a la barra de herramientas de acceso rápido (QAT).
  • Las galerías se pueden actualizar en tiempo de ejecución, en función de la actividad que se produce indirectamente desde el entorno en tiempo de ejecución, como cuando un controlador de impresora solo admite diseños de página verticales.
  • Las galerías se pueden actualizar en tiempo de ejecución, en función de la actividad que se produce indirectamente en la aplicación host, como cuando un usuario selecciona un elemento de un documento.

El marco de la cinta expone dos tipos de galerías: galerías de elementos y galerías de comandos.

Galerías de elementos

Las galerías de elementos contienen una colección basada en índices de elementos relacionados donde cada elemento se representa mediante una imagen, una cadena o ambos. El control se enlaza a un único controlador de comandos que se basa en el valor de índice identificado por la propiedad UI_PKEY_SelectedItem .

Las galerías de elementos admiten la vista previa dinámica, lo que significa mostrar un resultado de comando, basado en la conmutación por mouse o el foco, sin confirmar o invocar realmente el comando.

Importante

El marco de trabajo no admite galerías de elementos de hospedaje en el menú aplicación.

 

Galerías de comandos

Las galerías de comandos contienen una colección de elementos distintos no indexados. Cada elemento se representa mediante un único control enlazado a un controlador de comandos a través de un identificador de comando. Al igual que los controles independientes, cada elemento de una galería de comandos enruta los eventos de entrada a un controlador de comandos asociado; la propia galería de comandos no escucha eventos.

Las galerías de comandos no admiten la vista previa dinámica.

Hay cuatro controles de galería en el marco de la cinta: DropDownGallery, SplitButtonGallery, InRibbonGallery y ComboBox. Excepto comboBox , se puede implementar como una galería de elementos o una galería de comandos.

DropDownGallery es un botón que muestra una lista desplegable que contiene una colección de elementos o comandos mutuamente excluyentes.

En la captura de pantalla siguiente se muestra el control Galería desplegable de la cinta de opciones en Microsoft Paint para Windows 7.

captura de pantalla de un control de galería desplegable en microsoft paint para Windows 7.

SplitButtonGallery

SplitButtonGallery es un control compuesto que expone un único elemento predeterminado o Command de su colección en un botón principal y muestra otros elementos o comandos en una lista desplegable mutuamente excluyente que se muestra cuando se hace clic en un botón secundario.

En la captura de pantalla siguiente se muestra el control Galería de botones de división de la cinta de opciones en Microsoft Paint para Windows 7.

captura de pantalla de un control de galería de botones divididos en microsoft paint para Windows 7.

InRibbonGallery

InRibbonGallery es una galería que muestra una colección de elementos relacionados o Comandos en la cinta de opciones. Si hay demasiados elementos en la galería, se proporciona una flecha de expansión para mostrar el resto de la colección en un panel expandido.

En la captura de pantalla siguiente se muestra el control De la Galería de la cinta de opciones en Microsoft Paint para Windows 7.

captura de pantalla de un control de la galería en la cinta de opciones de microsoft paint.

ComboBox

Un ComboBox es un cuadro de lista de una sola columna que contiene una colección de elementos con un control estático o un control de edición y una flecha desplegable. La parte del cuadro de lista del control se muestra cuando el usuario hace clic en la flecha desplegable.

En la captura de pantalla siguiente se muestra un control Cuadro combinado de cinta de opciones de Windows Live Movie Maker.

captura de pantalla de un control de cuadro combinado en la cinta de microsoft paint.

Dado que comboBox es exclusivamente una galería de elementos, no admite elementos command. También es el único control de la galería que no admite un espacio de comandos. (Un espacio de comandos es una colección de comandos que se declaran en el marcado y se muestran en la parte inferior de una galería de elementos o galería de comandos).

En el ejemplo de código siguiente se muestra el marcado necesario para declarar un espacio de comandos de tres botones en una dropDownGallery.

<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>

En la captura de pantalla siguiente se muestra el espacio de comandos de tres botones del ejemplo de código anterior.

captura de pantalla de un espacio de comandos de tres botones en una lista desplegable.

En esta sección se describen los detalles de implementación de las galerías de la cinta de opciones y se explica cómo incorporarlos en una aplicación de cinta de opciones.

Componentes básicos

En esta sección se describe el conjunto de propiedades y métodos que forman la red troncal del contenido dinámico en el marco de la cinta de opciones y se admite la adición, eliminación, actualización y manipulación del contenido y el diseño visual de las galerías de la cinta en tiempo de ejecución.

IUICollection

Las galerías requieren un conjunto básico de métodos para acceder a los elementos individuales de sus colecciones y manipularlos.

La interfaz IEnumUnknown define estos métodos y el marco complementa su funcionalidad con métodos adicionales definidos en la interfaz IUICollection . IUICollection se implementa mediante el marco para cada declaración de galería en el marcado de cinta de opciones.

Si se requiere funcionalidad adicional que no se proporciona en la interfaz IUICollection , se puede sustituir un objeto de colección personalizado implementado por la aplicación host y derivado de IEnumUnknown para la colección de marcos.

IUICollectionChangedEvent

Para que una aplicación responda a los cambios en una colección de galerías, debe implementar la interfaz IUICollectionChangedEvent . Las aplicaciones pueden suscribirse a notificaciones desde un objeto IUICollection a través del agente de escucha de eventos IUICollectionChangedEvent::OnChanged .

Cuando la aplicación reemplaza la colección de galería proporcionada por el marco con una colección personalizada, la aplicación debe implementar la interfaz IConnectionPointContainer . Si IConnectionPointContainer no está implementado, la aplicación no puede notificar al marco de trabajo los cambios en la colección personalizada que requieren actualizaciones dinámicas en el control de galería.

En aquellos casos en los que IConnectionPointContainer no está implementado, el control de galería solo se puede actualizar mediante invalidación a través de IUIFramework::InvalidateUICommand y IUICommandHandler::UpdateProperty o llamando a IUIFramework::SetUICommandProperty.

IUISimplePropertySet

Las aplicaciones deben implementar IUISimplePropertySet para cada elemento o Command en una colección de galerías. Sin embargo, las propiedades que se pueden solicitar con IUISimplePropertySet::GetValue varían.

Los elementos se definen y enlazan a una galería a través de la clave de propiedad UI_PKEY_ItemsSource y exponen propiedades con un objeto IUICollection .

Las propiedades válidas para los elementos de galerías de elementos (UI_COMMANDTYPE_COLLECTION) se describen en la tabla siguiente.

Nota

Algunas propiedades de elemento, como UI_PKEY_Label, se pueden definir en el marcado. Para obtener más información, consulte la documentación de referencia de claves de propiedad.

 

Control

Propiedades

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 es una propiedad de la galería de elementos.

 

Las propiedades de elemento válidas para galerías de comandos (UI_COMMANDTYPE_COMMANDCOLLECTION) se describen en la tabla siguiente.

Control Propiedades
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

 

Las categorías se usan para organizar elementos y comandos en galerías. Las categorías se definen y enlazan a una galería a través de la clave de propiedad UI_PKEY_Categories y exponen propiedades con un objeto IUICollection específico de la categoría.

Las categorías no tienen un commandType y no admiten la interacción del usuario. Por ejemplo, las categorías no se pueden convertir en SelectedItem en una galería de elementos y no están enlazadas a un comando en una galería de comandos. Al igual que otras propiedades de elementos de la galería, se pueden recuperar propiedades de categoría como UI_PKEY_Label y UI_PKEY_CategoryId llamando a IUISimplePropertySet::GetValue.

Importante

IUISimplePropertySet::GetValue debe devolver UI_COLLECTION_INVALIDINDEX cuando se solicita UI_PKEY_CategoryId para un elemento que no tiene una categoría asociada.

 

Declarar los controles en marcado

Las galerías, como todos los controles de cinta, deben declararse en el marcado. Una galería se identifica en el marcado como una galería de elementos o la galería de comandos, y se declaran varios detalles de presentación. A diferencia de otros controles, las galerías solo requieren que el control base o el contenedor de colecciones se declaren en el marcado. Las colecciones reales se rellenan en tiempo de ejecución. Cuando se declara una galería en el marcado, el atributo Type se usa para especificar si la galería es una galería de elementos de una galería de comandos.

Hay varios atributos de diseño opcionales disponibles para cada uno de los controles que se describen aquí. Estos atributos proporcionan preferencias de desarrollador para que el marco siga que afecten directamente a cómo se rellena y se muestra un control en una cinta de opciones. Las preferencias aplicables en el marcado están relacionadas con las plantillas de presentación y diseño y los comportamientos descritos en Personalización de una cinta de opciones mediante definiciones de tamaño y directivas de escalado.

Si un control determinado no permite las preferencias de diseño directamente en el marcado o no se especifican las preferencias de diseño, el marco define convenciones de visualización específicas del control en función de la cantidad de espacio de pantalla disponible.

En los ejemplos siguientes se muestra cómo incorporar un conjunto de galerías en una cinta de opciones.

Declaraciones de comandos

Los comandos deben declararse con un atributo CommandName que se usa para asociar un control, o conjunto de controles, con el comando .

Un atributo CommandId que se usa para enlazar un comando a un controlador de comandos cuando se compila el marcado también se puede especificar aquí. Si no se proporciona ningún identificador, el marco genera uno.

<!-- 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"

Declaraciones de control

Esta sección contiene ejemplos que muestran el marcado de control básico necesario para los distintos tipos de galería. Muestran cómo declarar los controles de la galería y asociarlos a un comando mediante el atributo CommandName .

En el ejemplo siguiente se muestra una declaración de control para DropDownGallery donde se usa el atributo Type para especificar que se trata de una galería de comandos.

<!-- 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>

En el ejemplo siguiente se muestra una declaración de control para 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>

En el ejemplo siguiente se muestra una declaración de control para InRibbonGallery.

Nota

Dado que InRibbonGallery está diseñado para mostrar un subconjunto de su colección de elementos en la cinta de opciones sin activar un menú desplegable, proporciona una serie de atributos opcionales que rigen su tamaño y diseño de elementos en la inicialización de la cinta de opciones. Estos atributos son exclusivos de InRibbonGallery y no están disponibles en los demás controles dinámicos.

 

<!-- 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>

En el ejemplo siguiente se muestra una declaración de control para comboBox.

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

Crear un controlador de comandos

Para cada comando, el marco de la cinta de opciones requiere un controlador de comandos correspondiente en la aplicación host. Los controladores de comandos se implementan mediante la aplicación host de cinta de opciones y se derivan de la interfaz IUICommandHandler .

Nota

Varios comandos se pueden enlazar a un único controlador de comandos.

 

Un controlador de comandos tiene dos propósitos:

  • IUICommandHandler::UpdateProperty responde a las solicitudes de actualización de propiedades. Los valores de las propiedades Command, como UI_PKEY_Enabled o UI_PKEY_Label, se establecen mediante llamadas a IUIFramework::SetUICommandProperty o IUIFramework::InvalidateUICommand.
  • IUICommandHandler::Execute responde a eventos de ejecución. Este método admite los tres estados de ejecución siguientes especificados por el parámetro UI_EXECUTIONVERB .
    • El estado Execute se ejecuta, o confirma en, los comandos a los que está enlazado el controlador.
    • El estado de vista previa previsualiza los comandos a los que está enlazado el controlador. Básicamente, ejecuta los comandos sin confirmar el resultado.
    • El estado CancelPreview cancela los comandos en versión preliminar. Esto es necesario para admitir el recorrido a través de un menú o lista y obtener una vista previa secuencial y deshacer los resultados según sea necesario.

En el ejemplo siguiente se muestra un controlador de comandos de la galería.

/*
 * 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;
  }
};

Enlazar el controlador de comandos

Después de definir un controlador de comandos, el comando debe enlazarse al controlador.

En el ejemplo siguiente se muestra cómo enlazar un comando de galería a un controlador de comandos específico. En este caso, los controles ComboBox y gallery están enlazados a sus respectivos controladores de comandos.

// 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.
  }
}

Inicialización de una colección

En el ejemplo siguiente se muestra una implementación personalizada de IUISimplePropertySet para galerías de elementos y comandos.

La clase CItemProperties de este ejemplo se deriva de IUISimplePropertySet. Además del método requerido IUISimplePropertySet::GetValue, la clase CItemProperties implementa un conjunto de funciones auxiliares para la inicialización y el seguimiento de índices.

//
//  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;   
};

Controlar eventos de recopilación

En el ejemplo siguiente se muestra una implementación de IUICollectionChangedEvent.

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;
}

Propiedades de la colección

Creación de una aplicación de cinta de opciones

Descripción de comandos y controles

Directrices para la experiencia del usuario de la cinta

Proceso de diseño de cinta de opciones

Ejemplo de galería