갤러리 작업

Windows 리본 프레임워크는 개발자에게 다양한 컬렉션 기반 컨트롤에서 동적 콘텐츠를 관리하기 위한 강력하고 일관된 모델을 제공합니다. 리본 UI를 조정하고 다시 구성하면 이러한 동적 컨트롤을 통해 프레임워크가 호스트 애플리케이션과 리본 자체 모두에서 사용자 상호 작용에 응답하고 다양한 런타임 환경을 유연하게 처리할 수 있습니다.

소개

런타임 조건, 애플리케이션 요구 사항 및 최종 사용자 입력에 동적으로 적응하는 리본 프레임워크의 이 기능은 프레임워크의 풍부한 UI 기능을 강조 표시하고 개발자에게 광범위한 고객 요구를 충족할 수 있는 유연성을 제공합니다.

이 가이드의 초점은 프레임워크에서 지원하는 동적 갤러리 컨트롤을 설명하고, 차이점을 설명하고, 가장 잘 사용될 수 있는 시기와 위치를 논의하고, 리본 애플리케이션에 통합할 수 있는 방법을 보여 주는 것입니다.

갤러리

갤러리는 기능적이고 그래픽이 풍부한 목록 상자 컨트롤입니다. 갤러리의 항목 컬렉션은 범주별로 구성될 수 있으며, 유연한 열 및 행 기반 레이아웃으로 표시되고, 이미지와 텍스트로 표현되며, 갤러리 유형에 따라 라이브 미리 보기를 지원합니다.

갤러리는 다음과 같은 이유로 다른 동적 리본 컨트롤과 기능적으로 구별됩니다.

  • 갤러리는 갤러리 항목 컬렉션을 조작하기 위한 다양한 메서드를 정의하는 IUICollection 인터페이스를 구현합니다.
  • 사용자가 QAT(빠른 실행 도구 모음)에 명령을 추가하는 경우와 같이 리본에서 직접 발생하는 활동에 따라 런타임에 갤러리를 업데이트할 수 있습니다.
  • 프린터 드라이버가 세로 페이지 레이아웃만 지원하는 경우와 같이 런타임 환경에서 간접적으로 발생하는 활동에 따라 런타임에 갤러리를 업데이트할 수 있습니다.
  • 사용자가 문서에서 항목을 선택하는 경우와 같이 호스트 애플리케이션에서 간접적으로 발생하는 활동에 따라 런타임에 갤러리를 업데이트할 수 있습니다.

리본 프레임워크는 항목 갤러리와 명령 갤러리라는 두 가지 유형의 갤러리를 노출합니다.

항목 갤러리

항목 갤러리에는 각 항목이 이미지, 문자열 또는 둘 다로 표시되는 관련 항목의 인덱스 기반 컬렉션이 포함되어 있습니다. 컨트롤은 UI_PKEY_SelectedItem 속성으로 식별되는 인덱스 값을 사용하는 단일 Command 처리기에 바인딩됩니다.

항목 갤러리는 라이브 미리 보기를 지원합니다. 즉, 명령을 커밋하거나 실제로 호출하지 않고 마우스오버 또는 포커스에 따라 명령 결과를 표시합니다.

중요

프레임워크는 애플리케이션 메뉴에서 항목 갤러리 호스팅을 지원하지 않습니다.

 

명령 갤러리

명령 갤러리에는 인덱싱되지 않은 고유한 항목의 컬렉션이 포함되어 있습니다. 각 항목은 명령 ID를 통해 명령 처리기에 바인딩된 단일 컨트롤로 표시됩니다. 독립 실행형 컨트롤과 마찬가지로 명령 갤러리의 각 항목은 입력 이벤트를 연결된 명령 처리기로 라우팅합니다. 명령 갤러리 자체는 이벤트를 수신 대기하지 않습니다.

명령 갤러리는 라이브 미리 보기를 지원하지 않습니다.

리본 프레임워크에는 DropDownGallery, SplitButtonGallery, InRibbonGalleryComboBox의 네 가지 갤러리 컨트롤이 있습니다. ComboBox를 제외한 모든 항목 갤러리 또는 명령 갤러리로 구현할 수 있습니다.

DropDownGallery는 상호 배타적인 항목 또는 명령 컬렉션이 포함된 드롭다운 목록을 표시하는 단추입니다.

다음 스크린샷에서는 Windows 7용 Microsoft 그림판 리본 드롭다운 갤러리 컨트롤을 보여 줍니다.

Windows 7용 Microsoft 페인트의 드롭다운 갤러리 컨트롤 스크린샷

SplitButtonGallery

SplitButtonGallery는 기본 단추의 컬렉션에서 단일 기본 항목 또는 명령을 노출하고 보조 단추를 클릭할 때 표시되는 상호 배타적 드롭다운 목록에 다른 항목 또는 명령을 표시하는 복합 컨트롤입니다.

다음 스크린샷에서는 Windows 7용 Microsoft 그림판 리본 분할 단추 갤러리 컨트롤을 보여 줍니다.

Windows 7용 Microsoft 페인트의 분할 단추 갤러리 컨트롤 스크린샷.

InRibbonGallery

InRibbonGallery는 리본 메뉴에 관련된 항목 또는 명령 컬렉션을 표시하는 갤러리입니다. 갤러리에 항목이 너무 많은 경우 확장된 창에 컬렉션의 나머지 부분을 표시하기 위해 확장 화살표가 제공됩니다.

다음 스크린샷은 Windows 7용 Microsoft 그림판 리본 메뉴 갤러리 컨트롤을 보여 줍니다.

Microsoft 그림판 리본에 있는 리본 갤러리 컨트롤의 스크린샷

ComboBox

ComboBox는 정적 컨트롤 또는 편집 컨트롤 및 드롭다운 화살표가 있는 항목 컬렉션을 포함하는 단일 열 목록 상자입니다. 사용자가 드롭다운 화살표를 클릭하면 컨트롤의 목록 상자 부분이 표시됩니다.

다음 스크린샷에서는 Windows Live 무비 메이커 리본 콤보 상자 컨트롤을 보여 줍니다.

Microsoft 그림판 리본에 있는 콤보박스 컨트롤의 스크린샷

ComboBox는 독점적으로 항목 갤러리이므로 명령 항목을 지원하지 않습니다. 명령 공간을 지원하지 않는 유일한 갤러리 컨트롤이기도 합니다. (명령 공간은 태그에 선언되고 항목 갤러리 또는 명령 갤러리의 맨 아래에 나열되는 명령의 컬렉션입니다.)

다음 코드 예제에서는 DropDownGallery에서 3개의 단추 명령 공간을 선언하는 데 필요한 태그를 보여 줍니다.

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

다음 스크린샷은 이전 코드 예제의 3개 단추 명령 공간을 보여 줍니다.

드롭다운갤러리의 3개 단추 명령 공간 스크린샷.

이 섹션에서는 리본 갤러리의 구현 세부 정보를 설명하고 리본 애플리케이션에 통합하는 방법을 안내합니다.

기본 구성 요소

이 섹션에서는 리본 프레임워크에서 동적 콘텐츠의 중추를 형성하고 런타임에 리본 갤러리의 콘텐츠 및 시각적 레이아웃 추가, 삭제, 업데이트 및 기타 조작을 지원하는 속성 및 메서드 집합에 대해 설명합니다.

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_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 항목 갤러리의 속성입니다.

 

명령 갤러리(UI_COMMANDTYPE_COMMANDCOLLECTION)에 대한 유효한 항목 속성은 다음 표에 설명되어 있습니다.

제어 속성
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

 

범주는 갤러리에서 항목 및 명령을 구성하는 데 사용됩니다. 범주는 UI_PKEY_Categories 속성 키를 통해 정의되고 갤러리에 바인딩되며 범주별 IUICollection 개체를 사용하여 속성을 노출합니다.

범주에는 CommandType이 없으며 사용자 상호 작용을 지원하지 않습니다. 예를 들어 범주는 항목 갤러리에서 SelectedItem이 될 수 없으며 명령 갤러리의 명령에 바인딩되지 않습니다. 다른 갤러리 항목 속성과 마찬가지로 UI_PKEY_LabelUI_PKEY_CategoryId 같은 범주 속성은 IUISimplePropertySet::GetValue를 호출하여 검색할 수 있습니다.

중요

IUISimplePropertySet::GetValue는 연결된 범주가 없는 항목에 대해 UI_PKEY_CategoryId 요청하면 UI_COLLECTION_INVALIDINDEX 반환해야 합니다.

 

태그에서 컨트롤 선언

모든 리본 컨트롤과 마찬가지로 갤러리는 태그에 선언되어야 합니다. 갤러리는 태그에서 항목 갤러리 또는 명령 갤러리로 식별되며 다양한 프레젠테이션 세부 정보가 선언됩니다. 다른 컨트롤과 달리 갤러리는 태그에서 선언해야 하는 기본 컨트롤 또는 컬렉션 컨테이너만 필요합니다. 실제 컬렉션은 런타임에 채워집니다. 태그에 갤러리가 선언되면 Type 특성은 갤러리가 명령 갤러리의 항목 갤러리인지 여부를 지정하는 데 사용됩니다.

여기에서 설명하는 각 컨트롤에 사용할 수 있는 다양한 선택적 레이아웃 특성이 있습니다. 이러한 특성은 컨트롤이 채워지고 리본에 표시되는 방식에 직접적인 영향을 주는 프레임워크에 대한 개발자 기본 설정을 제공합니다. 태그에 적용할 수 있는 기본 설정은 크기 정의 및 크기 조정 정책을 통해 리본 사용자 지정에 설명된 표시 및 레이아웃 템플릿 및 동작과 관련이 있습니다.

특정 컨트롤이 태그에서 직접 레이아웃 기본 설정을 허용하지 않거나 레이아웃 기본 설정을 지정하지 않은 경우 프레임워크는 사용 가능한 화면 공간의 양에 따라 컨트롤별 표시 규칙을 정의합니다.

다음 예제에서는 갤러리 집합을 리본 메뉴에 통합하는 방법을 보여 줍니다.

명령 선언

명령은 컨트롤 또는 컨트롤 집합을 명령과 연결하는 데 사용되는 CommandName 특성으로 선언해야 합니다.

태그가 컴파일될 때 Command 처리기에 명령을 바인딩하는 데 사용되는 CommandId 특성도 여기에 지정할 수 있습니다. ID가 제공되지 않으면 프레임워크에서 ID가 생성됩니다.

<!-- 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와 연결하는 방법을 보여 줍니다.

다음 예제에서는 Type 특성이 명령 갤러리임을 지정하는 데 사용되는 DropDownGallery에 대한 컨트롤 선언을 보여줍니다.

<!-- 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 인터페이스에서 파생됩니다.

참고

여러 명령을 단일 명령 처리기에 바인딩할 수 있습니다.

 

명령 처리기는 다음 두 가지 용도로 사용됩니다.

  • IUICommandHandler::UpdateProperty 는 속성 업데이트 요청에 응답합니다. UI_PKEY_Enabled 또는 UI_PKEY_Label 같은 Command 속성 값은 IUIFramework::SetUICommandProperty 또는 IUIFramework::InvalidateUICommand에 대한 호출을 통해 설정됩니다.
  • IUICommandHandler::Execute 는 실행 이벤트에 응답합니다. 이 메서드는 UI_EXECUTIONVERB 매개 변수에 의해 지정된 다음 세 가지 실행 상태를 지원합니다.
    • Execute 상태는 처리기가 바인딩된 모든 명령을 실행하거나 커밋합니다.
    • 미리 보기 상태는 처리기가 바인딩된 모든 명령을 미리 봅니다. 기본적으로 결과에 커밋하지 않고 명령을 실행합니다.
    • CancelPreview 상태는 미리 보기된 명령을 취소합니다. 메뉴 또는 목록을 통한 순회를 지원하고 필요에 따라 결과를 순차적으로 미리 보기 및 실행 취소하는 데 필요합니다.

다음 예제에서는 갤러리 명령 처리기를 보여 줍니다.

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

명령 처리기 바인딩

명령 처리기를 정의한 후에는 명령이 처리기에 바인딩되어야 합니다.

다음 예제에서는 갤러리 명령을 특정 명령 처리기에 바인딩하는 방법을 보여 줍니다. 이 경우 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;
}

컬렉션 속성

리본 애플리케이션 만들기

명령 및 컨트롤 이해

리본 사용자 환경 지침

리본 디자인 프로세스

갤러리 샘플