使用資源庫

Windows 功能區架構為開發人員提供健全且一致的模型,可跨各種集合型控制項管理動態內容。 藉由調整及重新設定功能區 UI,這些動態控制項可讓架構回應主應用程式和功能區本身中的使用者互動,並提供處理各種執行時間環境的彈性。

簡介

功能區架構的這項功能,可動態適應執行時間條件、應用程式需求和使用者輸入,強調架構的豐富 UI 功能,並讓開發人員彈性地滿足各種客戶需求。

本指南的重點在於描述架構支援的動態資源庫控制項、說明其差異、討論其使用時機和位置,並示範如何納入功能區應用程式。

資源庫

資源庫的功能和圖形化豐富清單方塊控制項。 資源庫的專案集合可以依類別組織、以彈性資料行和資料列為基礎的版面配置、以影像和文字表示,以及視資源庫類型而定,支援即時預覽。

資源庫的運作方式與其他動態功能區控制項不同,原因如下:

  • 資源庫會實作 IUICollection 介面,這個介面會定義用於操作資源庫專案集合的各種方法。
  • 資源庫可以在執行時間更新,根據直接在功能區中發生的活動,例如當使用者將命令新增至快速存取工具列 (QAT) 時。
  • 資源庫可以在執行時間更新,根據從執行時間環境間接發生的活動,例如印表機驅動程式僅支援直向版面配置時。
  • 資源庫可以在執行時間更新,根據在主應用程式中間接發生的活動,例如當使用者選取檔中的專案時。

功能區架構會公開兩種類型的資源庫:專案庫和命令庫。

專案庫

專案庫包含相關專案的索引型集合,其中每個專案都以影像、字串或兩者表示。 控制項系結至單一 Command 處理常式,該處理常式依賴 由 UI_PKEY_SelectedItem 屬性所識別的索引值。

專案庫支援即時預覽,這表示根據滑鼠切換或焦點顯示命令結果,而不需認可或實際叫用命令。

重要

架構不支援在應用程式功能表中裝載專案資源庫。

 

命令庫

命令庫包含不同的非索引項目目集合。 每個專案都是由透過命令識別碼系結至 Command 處理常式的單一控制項來表示。 如同獨立控制項,Command 資源庫中的每個專案都會將輸入事件路由傳送至相關聯的 Command 處理常式,命令庫本身不會接聽事件。

命令庫不支援即時預覽。

功能區架構中有四個資源庫控制項: DropDownGallerySplitButtonGalleryInRibbonGalleryComboBoxComboBox以外的所有專案都可以實作為專案庫或命令庫。

DropDownGallery是一個按鈕,會顯示包含互斥專案或命令集合的下拉式清單。

下列螢幕擷取畫面說明 Windows 7 Microsoft 小畫家的功能區下拉式庫控制項。

microsoft paint for windows 7 中下拉式資源庫控制項的螢幕擷取畫面。

SplitButtonGallery

SplitButtonGallery是複合控制項,會從主要按鈕上的集合公開單一預設專案或 Command,並在按一下次要按鈕時,在互斥的下拉式清單中顯示其他專案或命令。

下列螢幕擷取畫面說明 Windows 7 Microsoft 小畫家的功能區分割按鈕庫控制項。

Microsoft paint for windows 7 中分割按鈕庫控制項的螢幕擷取畫面。

InRibbonGallery

InRibbonGallery是一個資源庫,會顯示功能區中相關專案或命令的集合。 如果資源庫中有太多專案,則會提供展開箭號,以在展開的窗格中顯示集合的其餘部分。

下列螢幕擷取畫面說明 Windows 7 Microsoft 小畫家的功能區內資源庫控制項。

microsoft paint 功能區中功能區內資源庫控制項的螢幕擷取畫面。

ComboBox

ComboBox是單欄清單方塊,其中包含具有靜態控制項或編輯控制項和下拉式箭號的專案集合。 當使用者按一下下拉式箭號時,會顯示控制項的清單方塊部分。

下列螢幕擷取畫面說明Windows Live Movie Maker的功能區下拉式方塊控制項。

microsoft paint 功能區中下拉式方塊控制項的螢幕擷取畫面。

因為 ComboBox 是獨佔專案庫,所以不支援命令專案。 這也是不支援命令空間的唯一資源庫控制項。 (命令空間是在標記中宣告的命令集合,並列在專案庫或命令庫底部。)

下列程式碼範例顯示在 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>

下列螢幕擷取畫面說明上述程式碼範例的三按鈕命令空間。

下拉式清單中三個按鈕命令空間的螢幕擷取畫面。

本節討論功能區資源庫的實作詳細資料,並逐步解說如何在功能區應用程式中納入它們。

基本元件

本節描述一組屬性和方法,這些屬性和方法形成功能區架構中的動態內容骨幹,並支援在執行時間新增、刪除、更新,以及操作功能區資源庫的內容和視覺化配置。

IUICollection

資源庫需要一組基本的方法來存取及操作其集合中的個別專案。

IEnumUnknown介面會定義這些方法,而架構會以IUICollection介面中定義的其他方法來補充其功能。 IUICollection 是由功能區標記中每個資源庫宣告的架構所實作。

如果 IUICollection 介面未提供其他功能,則主應用程式所實作且衍生自 IEnumUnknown 的自訂集合物件可以取代架構集合。

IUICollectionChangedEvent

若要讓應用程式回應資源庫集合中的變更,它必須實作 IUICollectionChangedEvent 介面。 應用程式可以透過IUICollectionChangedEvent::OnChanged事件接聽程式訂閱來自 IUICollection物件的通知。

當應用程式以自訂集合取代架構所提供的資源庫集合時,應用程式應該實作 IConnectionPointContainer 介面。 如果未實作 IConnectionPointContainer ,則應用程式無法通知自訂集合中需要動態更新資源庫控制項的變更架構。

在未實作 IConnectionPointContainer 的情況下,資源庫控制項只能透過 IUIFramework::InvalidateUICommandIUICommandHandler::UpdateProperty或呼叫 IUIFramework::SetUICommandProperty來更新資源庫控制項。

IUISimplePropertySet

應用程式必須針對資源庫集合中的每個專案或 Command 實作 IUISimplePropertySet。 不過,可以使用 IUISimplePropertySet::GetValue 要求的屬性會有所不同。

專案會透過 UI_PKEY_ItemsSource 屬性索引鍵定義並系結至資源庫,並使用 IUICollection 物件公開屬性。

下表說明專案庫中專案的有效屬性, (UI_COMMANDTYPE_COLLECTION) 。

注意

某些專案屬性,例如 UI_PKEY_Label,可以在標記中定義。 如需詳細資訊,請參閱 屬性索引鍵 參考檔。

 

控制

屬性

ComboBox

UI_PKEY_LabelUI_PKEY_CategoryId

DropDownGallery

UI_PKEY_LabelUI_PKEY_ItemImageUI_PKEY_CategoryId

InRibbonGallery

UI_PKEY_LabelUI_PKEY_ItemImageUI_PKEY_CategoryId

SplitButtonGallery

UI_PKEY_LabelUI_PKEY_ItemImageUI_PKEY_CategoryId

UI_PKEY_SelectedItem 是專案庫的屬性。

 

下表說明 Command 資源庫 (UI_COMMANDTYPE_COMMANDCOLLECTION) 的有效專案屬性。

控制 屬性
DropDownGallery UI_PKEY_CommandIdUI_PKEY_CommandTypeUI_PKEY_CategoryId
InRibbonGallery UI_PKEY_CommandIdUI_PKEY_CommandTypeUI_PKEY_CategoryId
SplitButtonGallery UI_PKEY_CommandIdUI_PKEY_CommandType、UI_PKEY_CategoryId

 

類別可用來組織資源庫中的專案和命令。 類別會透過 UI_PKEY_Categories 屬性索引鍵定義並系結至資源庫,並使用類別特定的 IUICollection 物件公開屬性。

類別沒有 CommandType,而且不支援使用者互動。 例如,類別無法成為專案庫中的 SelectedItem,而且它們不會系結至命令庫中的 Command。 如同其他資源庫專案屬性,您可以呼叫IUISimplePropertySet::GetValue來擷取類別屬性,例如UI_PKEY_Label和UI_PKEY_CategoryId

重要

當要求UI_PKEY_CategoryId沒有相關聯類別的專案時IUISimplePropertySet::GetValue應該傳回UI_COLLECTION_INVALIDINDEX

 

在標記中宣告控制項

資源庫就像所有功能區控制項一樣,必須在標記中宣告。 資源庫會在標記中識別為專案庫或命令庫,並宣告各種簡報詳細資料。 不同于其他控制項,資源庫只需要在標記中宣告基底控制項或集合容器。 實際集合會在執行時間填入。 在標記中宣告資源庫時,會使用 Type 屬性來指定資源庫是否為命令庫的專案庫。

這裡討論的每個控制項都有一些選擇性的配置屬性可用。 這些屬性會為架構提供開發人員喜好設定,以直接影響控制項在功能區中填入和顯示的方式。 標記中適用的喜好設定與透過 大小定義和調整原則自訂功能區中所討論的顯示和版面配置範本和行為有關。

如果特定控制項不允許直接在標記中設定版面配置喜好設定,或未指定版面配置喜好設定,則架構會根據可用的螢幕空間量定義控制項特定的顯示慣例。

下列範例示範如何將一組資源庫併入功能區。

命令宣告

命令應該使用 CommandName 屬性來宣告,該屬性可用來將控制項或控制項集與 Command 產生關聯。

在編譯標記時,也可以使用 CommandId 屬性將命令系結至 Command 處理常式。您也可以在這裡指定。 如果未提供任何識別碼,則架構會產生一個識別碼。

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

控制項宣告

本節包含範例,示範各種資源庫類型所需的基本控制項標記。 它們示範如何宣告資源庫控制項,並透過 CommandName 屬性將其與 Command 產生關聯。

下列範例顯示 DropDownGallery 的控制項宣告,其中 Type 屬性用來指定這是命令庫。

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

下列範例顯示 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>

下列範例顯示 InRibbonGallery的控制項宣告。

注意

由於 InRibbonGallery 的設計目的是要在功能區中顯示其專案集合的子集,而不啟用下拉式功能表,因此它提供一些選擇性屬性,以控管功能區初始化上的大小和專案配置。 這些屬性對 InRibbonGallery 而言是唯一的,無法從其他動態控制項取得。

 

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

下列範例顯示 ComboBox的控制項宣告。

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

建立命令處理常式

針對每個命令,功能區架構都需要主應用程式中對應的命令處理常式。 命令處理常式是由功能區主機應用程式實作,並且衍生自 IUICommandHandler 介面。

注意

多個命令可以系結至單一命令處理常式。

 

命令處理常式有兩個用途:

下列範例示範資源庫命令處理常式。

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

系結命令處理常式

定義 Command 處理常式之後,命令必須系結至處理常式。

下列範例示範如何將資源庫命令系結至特定的 Command 處理常式。 在此情況下, ComboBox 和資源庫控制項都會系結至其各自的命令處理常式。

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

初始化集合

下列範例示範專案和命令庫的 IUISimplePropertySet 自訂實作。

此範例中的 CItemProperties 類別衍生自 IUISimplePropertySet。 除了必要的 IUISimplePropertySet::GetValue方法之外,CItemProperties 類別還會實作一組協助程式函式來進行初始化和索引追蹤。

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

處理收集事件

下列範例示範 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;
}

集合屬性

建立功能區應用程式

瞭解命令和控制項

功能區使用者體驗指導方針

功能區設計程式

資源庫範例