SharePoint Ribbon. Создание многоуровневого меню

SharePoint 2010/2013 Ribbon API
SharePoint Ribbon. Использование ColorPicker'а
SharePoint Ribbon. Создание многоуровневого меню

Еще один сценарий применения QASPRibbon - создание многоуровневого меню.

В SharePoint меню на рибоне может быть использовано в следующих элементах: FlyoutAnchor, SplitButton, MRUSplitButon, DropDown и ComboBox. Каждое меню состоит из секций (MenuSection), которые могут содержать либо кнопки (Button) либо точки привязки (FlyoutAnchor) для отображения меню нижнего уровня.

Декларативно раскрывающийся список (DropDown), содержащий двухуровневое меню будет выглядеть примерно вот так (без указания атрибутов):

  1. <DropDown>
  2.   <Menu>
  3.     <Controls>
  4.       <MenuSection>
  5.         <Controls>
  6.           <Button><!-- Кнопка - пункт меню --></Button>
  7.           <FlyoutAnchor> <!-- Точка привязки меню -->
  8.             <Menu>
  9.               <Controls>
  10.                 <MenuSection>
  11.                   <Controls>
  12.                     <Button><!-- Кнопка - пункт меню --><Button>
  13.                   </Controls>
  14.                 </MenuSection>
  15.               </Controls>
  16.             </Menu>
  17.           </FlyoutAnchor>
  18.         </Controls>
  19.       </MenuSection>
  20.     </Controls>
  21.   </Menu>
  22. </DropDown>

В результате мы получим двухуровневое меню. Первый уровень будет содержать одну кнопку и ссылку на нижестоящий уровень с одной кнопкой.

Чтобы достичь того же результата, используя QASPRibbon, понадобится вот такой код:

  1. var dropDown = new RibbonDropDown("DropDownId""DropDownTitle")
  2. {
  3.     Sections = new[]
  4.     {
  5.         new RibbonMenuSection("SectionId""SectionTitle")
  6.         {
  7.             Controls = new RibbonControl[]
  8.             {
  9.                 new RibbonButton("ButtonId""ButtonTitle"),
  10.                 new RibbonFlyoutAnchor("FlyoutAnchorId""FlyoutAnchorTitle")
  11.                 {
  12.                     Sections = new[]
  13.                     {
  14.                         new RibbonMenuSection("SectionId""SectionTitle")
  15.                         {
  16.                             Controls = new RibbonControl[]
  17.                             {
  18.                                 new RibbonButton("ButtonId""ButtonTitle")
  19.                             }
  20.                         }
  21.                     }
  22.                 }
  23.             }
  24.         }
  25.     }
  26. };

Код на первый взгляд не менее "кудрявый". Но есть следующие неоспоримые плюсы:

  • Генерация меню динамически на основе каких-либо данных (тот же список в SharePoint) крайне проста. Использование метода .Select(x=> new RibbonButton(x.Id.ToString(), x.Title){...}) почти всегда достаточно. Можно написать 2-3 метода, которые будут генерировать правильный XML-код, но читабельность такого подхода будет ниже некуда. Инкапсуляция здесь очень облегчает задачу как разработки так и сопровождения решения;
  • Использование обработчиков на стороне сервера. Опять инкапсуляция, позволяющая избежать изобретения велосипеда;
  • Модификация созданного ribbon-элемента управления. В случае применения нативного API приходится парсить XML (одно только тестирование такого решения обойдется очень дорого). В случае использования классов задача становится крайне простой;

Создание меню

Для удобства создадим демо-метод, который будет возвращать секцию меню, описанную выше:

  1. private RibbonMenuSection[] GetFakeMenuSections()
  2. {
  3.     return new[]
  4.     {
  5.         new RibbonMenuSection("SectionId""SectionTitle")
  6.         {
  7.             //Картинка 32x32 + текст
  8.             DisplayMode = RibbonMenuDisplayMode.Menu32,
  9.             Controls = new RibbonControl[]
  10.             {
  11.                 new RibbonButton("ButtonId""ButtonTitle")
  12.                 {
  13.                     Image = RibbonImageDefinition.Standard(7, 7)
  14.                 },
  15.                 new RibbonFlyoutAnchor("FlyoutAnchorId""FlyoutAnchorTitle")
  16.                 {
  17.                     Image = RibbonImageDefinition.Standard(7, 7),
  18.                     Sections = new[]
  19.                     {
  20.                         new RibbonMenuSection("SectionId""SectionTitle")
  21.                         {
  22.                             Controls = new RibbonControl[]
  23.                             {
  24.                                 new RibbonButton("ButtonId""ButtonTitle")
  25.                                 {
  26.                                     Image = RibbonImageDefinition.Standard(7, 7)
  27.                                 }
  28.                             }
  29.                         }
  30.                     }
  31.                 }
  32.             }
  33.         }
  34.     };
  35. }

Это позволит уменьшить кол-во кода в дальнейшем.

Теперь перейдем непосредственного к созданию меню. Вот код, описывающий простую вкладку, дочернюю группу и элементы с выпадающими меню:

  1. // Новая закладка
  2. var menuTab = new RibbonTab("MenuTab""Menu demo tab")
  3. {
  4.     // Порядковый номер должен быть не кратен 100
  5.     Sequence = 550,
  6.     // Указыаем порядковый номер элемента
  7.     Groups = new[]
  8.     {
  9.         // Новая группа
  10.         new RibbonGroup("MenuGroup""Menu demo group")
  11.         {
  12.             // Располагаем элементы по центру
  13.             Alignment = RibbonGroupAlignment.Middle,
  14.             // Отображаем картинку и текст
  15.             DisplayMode = RibbonDisplayMode.Image16AndCaption,
  16.             // Разметка в две строки
  17.             Template = RibbonGroupTemplate.TwoRows,
  18.             Controls = new RibbonControl[]
  19.             {
  20.                 new RibbonDropDown("DropDownId""DropDownTitle")
  21.                 {
  22.                     Sections = GetFakeMenuSections()
  23.                 },
  24.                 new RibbonComboBox("ComboBoxId""ComboBoxTitle")
  25.                 {
  26.                     Sections = GetFakeMenuSections()
  27.                 },
  28.                 new RibbonFlyoutAnchor("FlyoutAnchorId""FlyoutAnchorTitle")
  29.                 {
  30.                     Image = RibbonImageDefinition.Standard(7, 8),
  31.                     Sections = GetFakeMenuSections()
  32.                 },
  33.                 new RibbonSplitButton("SplitButtonId""SplitButtonTitle")
  34.                 {
  35.                     Image = RibbonImageDefinition.Standard(7, 8),
  36.                     Sections = GetFakeMenuSections()
  37.                 }
  38.             }
  39.         }
  40.     }
  41. };

Очень простой и читабельный код. Я указал изображение для SplitButton, так как по мимо выпадающего меню это ещё и кнопка. Аналогично можно использовать и MRUSplitButton, но для него нужна разметка группы в одну строку.

В качестве разметки группы я использовал две строки (TwoRows). Какие ещё бывают разметки и как они выглядят можно посмотреть на странице проекта. Порядковый номер группы не должен быть кратен 100, т.к. такие номера используются стандартными вкладками SharePoint.

Теперь добавим вкладку на страницу:

  1. RibbonManager.Current.AddTabToPage(menuTab, Page);

И результат в браузере:

SharePoint Ribbon DropDown SharePoint Ribbon ComboBox SharePoint Ribbon FlyoutAnchor SharePoint Ribbon SplitButton

При выборе какого-либо пункта меню в DropDown или ComboBox соответствующий им контейнер заполняется текстом из выбранного пункта, т.е. пользователи смогут увидеть то, что они выбрали:

SharePoint Ribbon ComboBox

При использовании стандартных средств SharePoint для использования Ribbon, пришлось бы использовать вот такой XML-код:

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <Tab Id="Ribbon.MenuTab" Title="Menu demo tab" CssClass="" Sequence="550">
  3.  <Scaling Id="Ribbon.MenuTab.Scaling">
  4.   <MaxSize Id="Ribbon.MenuTab.MenuGroup.MaxSize" GroupId="Ribbon.MenuTab.MenuGroup" Size="Ribbon.MenuTab.MenuGroupLayout" Sequence="10" />
  5.  </Scaling>
  6.  <Groups Id="Ribbon.MenuTab.Groups">
  7.   <Group Id="Ribbon.MenuTab.MenuGroup" Title="Menu demo group" Description="" Sequence="1" Template="Ribbon.MenuTab.MenuGroupTemplate">
  8.    <Controls Id="Ribbon.MenuTab.MenuGroup.Controls">
  9.     <DropDown Id="Ribbon.MenuTab.MenuGroup.Controls.DropDownId" Sequence="1" Width="100px" TemplateAlias="Ribbon.MenuTab.MenuGroupLayout1MediumRowI" CacheMenuVersions="true" PopulateDynamically="false" PopulateOnlyOnce="false" QueryCommand="Ribbon.MenuTab.MenuGroup.Controls.DropDownIdQueryCommand" Command="Ribbon.MenuTab.MenuGroup.Controls.DropDownIdCommand" CommandMenuOpen="Ribbon.MenuTab.MenuGroup.Controls.DropDownIdCommandMenuOpen" CommandMenuClose="Ribbon.MenuTab.MenuGroup.Controls.DropDownIdCommandMenuClose">
  10.      <Menu Id="Ribbon.MenuTab.MenuGroup.Controls.DropDownId.Menu">
  11.       <MenuSection Id="Ribbon.MenuTab.MenuGroup.Controls.DropDownId.Menu.SectionId" Sequence="1" Title="SectionTitle" DisplayMode="Menu16" Scrollable="true">
  12.        <Controls Id="Ribbon.MenuTab.MenuGroup.Controls.DropDownId.Menu.SectionId.Controls">
  13.         <Button Id="Ribbon.MenuTab.MenuGroup.Controls.DropDownId.Menu.SectionId.Controls.ButtonId" Sequence="1" Image16by16="/_layouts/1033/images/formatmap16x16.png" Image32by32="/_layouts/1033/images/formatmap32x32.png" Image16by16Left="-112" Image32by32Left="-224" Image16by16Top="-112" Image32by32Top="-224" LabelText="ButtonTitle" MenuItemId="Ribbon.MenuTab.MenuGroup.Controls.DropDownId.Menu.SectionId.Controls.ButtonId" CommandValueId="Ribbon.MenuTab.MenuGroup.Controls.DropDownId.Menu.SectionId.Controls.ButtonIdCommand" Command="Ribbon.MenuTab.MenuGroup.Controls.DropDownId.Menu.SectionId.Controls.ButtonIdCommand" />
  14.         <FlyoutAnchor Id="Ribbon.MenuTab.MenuGroup.Controls.DropDownId.Menu.SectionId.Controls.FlyoutAnchorId" Sequence="2" Image16by16="/_layouts/1033/images/formatmap16x16.png" Image32by32="/_layouts/1033/images/formatmap32x32.png" Image16by16Left="-112" Image32by32Left="-224" Image16by16Top="-112" Image32by32Top="-224" LabelText="FlyoutAnchorTitle" TemplateAlias="" PopulateQueryCommand="Ribbon.MenuTab.MenuGroup.Controls.DropDownId.Menu.SectionId.Controls.FlyoutAnchorIdPopulateQueryCommand" CommandMenuClose="Ribbon.MenuTab.MenuGroup.Controls.DropDownId.Menu.SectionId.Controls.FlyoutAnchorIdCommandMenuClose" Command="Ribbon.MenuTab.MenuGroup.Controls.DropDownId.Menu.SectionId.Controls.FlyoutAnchorIdCommand" CommandQuery="Ribbon.MenuTab.MenuGroup.Controls.DropDownId.Menu.SectionId.Controls.FlyoutAnchorIdCommandQuery" CacheMenuVersions="true" PopulateDynamically="false" PopulateOnlyOnce="false">
  15.          <Menu Id="Ribbon.MenuTab.MenuGroup.Controls.DropDownId.Menu.SectionId.Controls.FlyoutAnchorId.Menu">
  16.           <MenuSection Id="Ribbon.MenuTab.MenuGroup.Controls.DropDownId.Menu.SectionId.Controls.FlyoutAnchorId.Menu.SectionId" Sequence="1" Title="SectionTitle" DisplayMode="Menu32" Scrollable="true">
  17.            <Controls Id="Ribbon.MenuTab.MenuGroup.Controls.DropDownId.Menu.SectionId.Controls.FlyoutAnchorId.Menu.SectionId.Controls">
  18.             <Button Id="Ribbon.MenuTab.MenuGroup.Controls.DropDownId.Menu.SectionId.Controls.FlyoutAnchorId.Menu.SectionId.Controls.ButtonId" Sequence="1" Image16by16="/_layouts/1033/images/formatmap16x16.png" Image32by32="/_layouts/1033/images/formatmap32x32.png" Image16by16Left="-112" Image32by32Left="-224" Image16by16Top="-112" Image32by32Top="-224" LabelText="ButtonTitle" MenuItemId="Ribbon.MenuTab.MenuGroup.Controls.DropDownId.Menu.SectionId.Controls.FlyoutAnchorId.Menu.SectionId.Controls.ButtonId" CommandValueId="Ribbon.MenuTab.MenuGroup.Controls.DropDownId.Menu.SectionId.Controls.FlyoutAnchorId.Menu.SectionId.Controls.ButtonIdCommand" Command="Ribbon.MenuTab.MenuGroup.Controls.DropDownId.Menu.SectionId.Controls.FlyoutAnchorId.Menu.SectionId.Controls.ButtonIdCommand" />
  19.            </Controls>
  20.           </MenuSection>
  21.          </Menu>
  22.         </FlyoutAnchor>
  23.        </Controls>
  24.       </MenuSection>
  25.      </Menu>
  26.     </DropDown>
  27.     <ComboBox Id="Ribbon.MenuTab.MenuGroup.Controls.ComboBoxId" Sequence="2" Width="100px" AutoComplete="true" AutoCompleteDelay="100" AllowFreeForm="false" TemplateAlias="Ribbon.MenuTab.MenuGroupLayout1MediumRowII" CacheMenuVersions="false" PopulateDynamically="false" PopulateOnlyOnce="false" QueryCommand="Ribbon.MenuTab.MenuGroup.Controls.ComboBoxIdQueryCommand" Command="Ribbon.MenuTab.MenuGroup.Controls.ComboBoxIdCommand" CommandMenuOpen="Ribbon.MenuTab.MenuGroup.Controls.ComboBoxIdCommandMenuOpen" CommandMenuClose="Ribbon.MenuTab.MenuGroup.Controls.ComboBoxIdCommandMenuClose" InitialItem="Ribbon.MenuTab.MenuGroup.Controls.ComboBoxId.Menu.SectionId.Controls.ButtonId">
  28.      <Menu Id="Ribbon.MenuTab.MenuGroup.Controls.ComboBoxId.Menu">
  29.       <MenuSection Id="Ribbon.MenuTab.MenuGroup.Controls.ComboBoxId.Menu.SectionId" Sequence="1" Title="SectionTitle" DisplayMode="Menu16" Scrollable="true">
  30.        <Controls Id="Ribbon.MenuTab.MenuGroup.Controls.ComboBoxId.Menu.SectionId.Controls">
  31.         <Button Id="Ribbon.MenuTab.MenuGroup.Controls.ComboBoxId.Menu.SectionId.Controls.ButtonId" Sequence="1" Image16by16="/_layouts/1033/images/formatmap16x16.png" Image32by32="/_layouts/1033/images/formatmap32x32.png" Image16by16Left="-112" Image32by32Left="-224" Image16by16Top="-112" Image32by32Top="-224" LabelText="ButtonTitle" MenuItemId="Ribbon.MenuTab.MenuGroup.Controls.ComboBoxId.Menu.SectionId.Controls.ButtonId" CommandValueId="Ribbon.MenuTab.MenuGroup.Controls.ComboBoxId.Menu.SectionId.Controls.ButtonIdCommand" Command="Ribbon.MenuTab.MenuGroup.Controls.ComboBoxId.Menu.SectionId.Controls.ButtonIdCommand" />
  32.         <FlyoutAnchor Id="Ribbon.MenuTab.MenuGroup.Controls.ComboBoxId.Menu.SectionId.Controls.FlyoutAnchorId" Sequence="2" Image16by16="/_layouts/1033/images/formatmap16x16.png" Image32by32="/_layouts/1033/images/formatmap32x32.png" Image16by16Left="-112" Image32by32Left="-224" Image16by16Top="-112" Image32by32Top="-224" LabelText="FlyoutAnchorTitle" TemplateAlias="" PopulateQueryCommand="Ribbon.MenuTab.MenuGroup.Controls.ComboBoxId.Menu.SectionId.Controls.FlyoutAnchorIdPopulateQueryCommand" CommandMenuClose="Ribbon.MenuTab.MenuGroup.Controls.ComboBoxId.Menu.SectionId.Controls.FlyoutAnchorIdCommandMenuClose" Command="Ribbon.MenuTab.MenuGroup.Controls.ComboBoxId.Menu.SectionId.Controls.FlyoutAnchorIdCommand" CommandQuery="Ribbon.MenuTab.MenuGroup.Controls.ComboBoxId.Menu.SectionId.Controls.FlyoutAnchorIdCommandQuery" CacheMenuVersions="true" PopulateDynamically="false" PopulateOnlyOnce="false">
  33.          <Menu Id="Ribbon.MenuTab.MenuGroup.Controls.ComboBoxId.Menu.SectionId.Controls.FlyoutAnchorId.Menu">
  34.           <MenuSection Id="Ribbon.MenuTab.MenuGroup.Controls.ComboBoxId.Menu.SectionId.Controls.FlyoutAnchorId.Menu.SectionId" Sequence="1" Title="SectionTitle" DisplayMode="Menu32" Scrollable="true">
  35.            <Controls Id="Ribbon.MenuTab.MenuGroup.Controls.ComboBoxId.Menu.SectionId.Controls.FlyoutAnchorId.Menu.SectionId.Controls">
  36.             <Button Id="Ribbon.MenuTab.MenuGroup.Controls.ComboBoxId.Menu.SectionId.Controls.FlyoutAnchorId.Menu.SectionId.Controls.ButtonId" Sequence="1" Image16by16="/_layouts/1033/images/formatmap16x16.png" Image32by32="/_layouts/1033/images/formatmap32x32.png" Image16by16Left="-112" Image32by32Left="-224" Image16by16Top="-112" Image32by32Top="-224" LabelText="ButtonTitle" MenuItemId="Ribbon.MenuTab.MenuGroup.Controls.ComboBoxId.Menu.SectionId.Controls.FlyoutAnchorId.Menu.SectionId.Controls.ButtonId" CommandValueId="Ribbon.MenuTab.MenuGroup.Controls.ComboBoxId.Menu.SectionId.Controls.FlyoutAnchorId.Menu.SectionId.Controls.ButtonIdCommand" Command="Ribbon.MenuTab.MenuGroup.Controls.ComboBoxId.Menu.SectionId.Controls.FlyoutAnchorId.Menu.SectionId.Controls.ButtonIdCommand" />
  37.            </Controls>
  38.           </MenuSection>
  39.          </Menu>
  40.         </FlyoutAnchor>
  41.        </Controls>
  42.       </MenuSection>
  43.      </Menu>
  44.     </ComboBox>
  45.     <FlyoutAnchor Id="Ribbon.MenuTab.MenuGroup.Controls.FlyoutAnchorId" Sequence="3" Image16by16="/_layouts/1033/images/formatmap16x16.png" Image32by32="/_layouts/1033/images/formatmap32x32.png" Image16by16Left="-112" Image32by32Left="-224" Image16by16Top="-128" Image32by32Top="-256" LabelText="FlyoutAnchorTitle" TemplateAlias="Ribbon.MenuTab.MenuGroupLayout2MediumRowI" PopulateQueryCommand="Ribbon.MenuTab.MenuGroup.Controls.FlyoutAnchorIdPopulateQueryCommand" CommandMenuClose="Ribbon.MenuTab.MenuGroup.Controls.FlyoutAnchorIdCommandMenuClose" Command="Ribbon.MenuTab.MenuGroup.Controls.FlyoutAnchorIdCommand" CommandQuery="Ribbon.MenuTab.MenuGroup.Controls.FlyoutAnchorIdCommandQuery" CacheMenuVersions="true" PopulateDynamically="false" PopulateOnlyOnce="false">
  46.      <Menu Id="Ribbon.MenuTab.MenuGroup.Controls.FlyoutAnchorId.Menu">
  47.       <MenuSection Id="Ribbon.MenuTab.MenuGroup.Controls.FlyoutAnchorId.Menu.SectionId" Sequence="1" Title="SectionTitle" DisplayMode="Menu16" Scrollable="true">
  48.        <Controls Id="Ribbon.MenuTab.MenuGroup.Controls.FlyoutAnchorId.Menu.SectionId.Controls">
  49.         <Button Id="Ribbon.MenuTab.MenuGroup.Controls.FlyoutAnchorId.Menu.SectionId.Controls.ButtonId" Sequence="1" Image16by16="/_layouts/1033/images/formatmap16x16.png" Image32by32="/_layouts/1033/images/formatmap32x32.png" Image16by16Left="-112" Image32by32Left="-224" Image16by16Top="-112" Image32by32Top="-224" LabelText="ButtonTitle" MenuItemId="Ribbon.MenuTab.MenuGroup.Controls.FlyoutAnchorId.Menu.SectionId.Controls.ButtonId" CommandValueId="Ribbon.MenuTab.MenuGroup.Controls.FlyoutAnchorId.Menu.SectionId.Controls.ButtonIdCommand" Command="Ribbon.MenuTab.MenuGroup.Controls.FlyoutAnchorId.Menu.SectionId.Controls.ButtonIdCommand" />
  50.         <FlyoutAnchor Id="Ribbon.MenuTab.MenuGroup.Controls.FlyoutAnchorId.Menu.SectionId.Controls.FlyoutAnchorId" Sequence="2" Image16by16="/_layouts/1033/images/formatmap16x16.png" Image32by32="/_layouts/1033/images/formatmap32x32.png" Image16by16Left="-112" Image32by32Left="-224" Image16by16Top="-112" Image32by32Top="-224" LabelText="FlyoutAnchorTitle" TemplateAlias="" PopulateQueryCommand="Ribbon.MenuTab.MenuGroup.Controls.FlyoutAnchorId.Menu.SectionId.Controls.FlyoutAnchorIdPopulateQueryCommand" CommandMenuClose="Ribbon.MenuTab.MenuGroup.Controls.FlyoutAnchorId.Menu.SectionId.Controls.FlyoutAnchorIdCommandMenuClose" Command="Ribbon.MenuTab.MenuGroup.Controls.FlyoutAnchorId.Menu.SectionId.Controls.FlyoutAnchorIdCommand" CommandQuery="Ribbon.MenuTab.MenuGroup.Controls.FlyoutAnchorId.Menu.SectionId.Controls.FlyoutAnchorIdCommandQuery" CacheMenuVersions="true" PopulateDynamically="false" PopulateOnlyOnce="false">
  51.          <Menu Id="Ribbon.MenuTab.MenuGroup.Controls.FlyoutAnchorId.Menu.SectionId.Controls.FlyoutAnchorId.Menu">
  52.           <MenuSection Id="Ribbon.MenuTab.MenuGroup.Controls.FlyoutAnchorId.Menu.SectionId.Controls.FlyoutAnchorId.Menu.SectionId" Sequence="1" Title="SectionTitle" DisplayMode="Menu32" Scrollable="true">
  53.            <Controls Id="Ribbon.MenuTab.MenuGroup.Controls.FlyoutAnchorId.Menu.SectionId.Controls.FlyoutAnchorId.Menu.SectionId.Controls">
  54.             <Button Id="Ribbon.MenuTab.MenuGroup.Controls.FlyoutAnchorId.Menu.SectionId.Controls.FlyoutAnchorId.Menu.SectionId.Controls.ButtonId" Sequence="1" Image16by16="/_layouts/1033/images/formatmap16x16.png" Image32by32="/_layouts/1033/images/formatmap32x32.png" Image16by16Left="-112" Image32by32Left="-224" Image16by16Top="-112" Image32by32Top="-224" LabelText="ButtonTitle" MenuItemId="Ribbon.MenuTab.MenuGroup.Controls.FlyoutAnchorId.Menu.SectionId.Controls.FlyoutAnchorId.Menu.SectionId.Controls.ButtonId" CommandValueId="Ribbon.MenuTab.MenuGroup.Controls.FlyoutAnchorId.Menu.SectionId.Controls.FlyoutAnchorId.Menu.SectionId.Controls.ButtonIdCommand" Command="Ribbon.MenuTab.MenuGroup.Controls.FlyoutAnchorId.Menu.SectionId.Controls.FlyoutAnchorId.Menu.SectionId.Controls.ButtonIdCommand" />
  55.            </Controls>
  56.           </MenuSection>
  57.          </Menu>
  58.         </FlyoutAnchor>
  59.        </Controls>
  60.       </MenuSection>
  61.      </Menu>
  62.     </FlyoutAnchor>
  63.     <SplitButton Id="Ribbon.MenuTab.MenuGroup.Controls.SplitButtonId" Sequence="4" Image16by16="/_layouts/1033/images/formatmap16x16.png" Image32by32="/_layouts/1033/images/formatmap32x32.png" Image16by16Left="-112" Image32by32Left="-224" Image16by16Top="-128" Image32by32Top="-256" LabelText="SplitButtonTitle" TemplateAlias="Ribbon.MenuTab.MenuGroupLayout2MediumRowII" MenuItemId="Ribbon.MenuTab.MenuGroup.Controls.SplitButtonId" CommandValueId="Ribbon.MenuTab.MenuGroup.Controls.SplitButtonIdCommand" Command="Ribbon.MenuTab.MenuGroup.Controls.SplitButtonIdCommand" CommandQuery="Ribbon.MenuTab.MenuGroup.Controls.SplitButtonIdCommandQuery">
  64.      <Menu Id="Ribbon.MenuTab.MenuGroup.Controls.SplitButtonId.Menu">
  65.       <MenuSection Id="Ribbon.MenuTab.MenuGroup.Controls.SplitButtonId.Menu.SectionId" Sequence="1" Title="SectionTitle" DisplayMode="Menu16" Scrollable="true">
  66.        <Controls Id="Ribbon.MenuTab.MenuGroup.Controls.SplitButtonId.Menu.SectionId.Controls">
  67.         <Button Id="Ribbon.MenuTab.MenuGroup.Controls.SplitButtonId.Menu.SectionId.Controls.ButtonId" Sequence="1" Image16by16="/_layouts/1033/images/formatmap16x16.png" Image32by32="/_layouts/1033/images/formatmap32x32.png" Image16by16Left="-112" Image32by32Left="-224" Image16by16Top="-112" Image32by32Top="-224" LabelText="ButtonTitle" MenuItemId="Ribbon.MenuTab.MenuGroup.Controls.SplitButtonId.Menu.SectionId.Controls.ButtonId" CommandValueId="Ribbon.MenuTab.MenuGroup.Controls.SplitButtonId.Menu.SectionId.Controls.ButtonIdCommand" Command="Ribbon.MenuTab.MenuGroup.Controls.SplitButtonId.Menu.SectionId.Controls.ButtonIdCommand" />
  68.         <FlyoutAnchor Id="Ribbon.MenuTab.MenuGroup.Controls.SplitButtonId.Menu.SectionId.Controls.FlyoutAnchorId" Sequence="2" Image16by16="/_layouts/1033/images/formatmap16x16.png" Image32by32="/_layouts/1033/images/formatmap32x32.png" Image16by16Left="-112" Image32by32Left="-224" Image16by16Top="-112" Image32by32Top="-224" LabelText="FlyoutAnchorTitle" TemplateAlias="" PopulateQueryCommand="Ribbon.MenuTab.MenuGroup.Controls.SplitButtonId.Menu.SectionId.Controls.FlyoutAnchorIdPopulateQueryCommand" CommandMenuClose="Ribbon.MenuTab.MenuGroup.Controls.SplitButtonId.Menu.SectionId.Controls.FlyoutAnchorIdCommandMenuClose" Command="Ribbon.MenuTab.MenuGroup.Controls.SplitButtonId.Menu.SectionId.Controls.FlyoutAnchorIdCommand" CommandQuery="Ribbon.MenuTab.MenuGroup.Controls.SplitButtonId.Menu.SectionId.Controls.FlyoutAnchorIdCommandQuery" CacheMenuVersions="true" PopulateDynamically="false" PopulateOnlyOnce="false">
  69.          <Menu Id="Ribbon.MenuTab.MenuGroup.Controls.SplitButtonId.Menu.SectionId.Controls.FlyoutAnchorId.Menu">
  70.           <MenuSection Id="Ribbon.MenuTab.MenuGroup.Controls.SplitButtonId.Menu.SectionId.Controls.FlyoutAnchorId.Menu.SectionId" Sequence="1" Title="SectionTitle" DisplayMode="Menu32" Scrollable="true">
  71.            <Controls Id="Ribbon.MenuTab.MenuGroup.Controls.SplitButtonId.Menu.SectionId.Controls.FlyoutAnchorId.Menu.SectionId.Controls">
  72.             <Button Id="Ribbon.MenuTab.MenuGroup.Controls.SplitButtonId.Menu.SectionId.Controls.FlyoutAnchorId.Menu.SectionId.Controls.ButtonId" Sequence="1" Image16by16="/_layouts/1033/images/formatmap16x16.png" Image32by32="/_layouts/1033/images/formatmap32x32.png" Image16by16Left="-112" Image32by32Left="-224" Image16by16Top="-112" Image32by32Top="-224" LabelText="ButtonTitle" MenuItemId="Ribbon.MenuTab.MenuGroup.Controls.SplitButtonId.Menu.SectionId.Controls.FlyoutAnchorId.Menu.SectionId.Controls.ButtonId" CommandValueId="Ribbon.MenuTab.MenuGroup.Controls.SplitButtonId.Menu.SectionId.Controls.FlyoutAnchorId.Menu.SectionId.Controls.ButtonIdCommand" Command="Ribbon.MenuTab.MenuGroup.Controls.SplitButtonId.Menu.SectionId.Controls.FlyoutAnchorId.Menu.SectionId.Controls.ButtonIdCommand" />
  73.            </Controls>
  74.           </MenuSection>
  75.          </Menu>
  76.         </FlyoutAnchor>
  77.        </Controls>
  78.       </MenuSection>
  79.      </Menu>
  80.     </SplitButton>
  81.    </Controls>
  82.   </Group>
  83.  </Groups>
  84. </Tab>

Напоследок про ComboBox. Он поддерживает автодополнение, но работает оно только для первого уровня меню. Все остальные пункты меню в результатах выводится не будут. Это не мешает выбирать их вручную.

Виталий Жуков

Виталий Жуков

SharePoint архитектор, разработчик, тренер, Microsoft MVP (Office Development). Более 15 лет опыта работы с SharePoint, Dynamics CRM, Office 365, и другими продуктами и сервисами Microsoft.

Смотрите также

Новый сайт группы SharePoint. Как это работает

Новый сайт группы SharePoint. Как это работает

SharePoint 2019 Preview

SharePoint 2019 Preview

Управление большими списками/библиотеками в SharePoint

Управление большими списками/библиотеками в SharePoint

SharePoint 2013/2016. Настройка хлебных крошек

SharePoint 2013/2016. Настройка хлебных крошек

SharePoint 2016. Кастомизация меню SuiteBar

SharePoint 2016. Кастомизация меню SuiteBar

SharePoint 2016. Кастомизация SuiteBar

SharePoint 2016. Кастомизация SuiteBar

Домашняя страница сайта SharePoint

Домашняя страница сайта SharePoint

Презентация и скрипты со встречи сообщества по SharePoint и Office 365

Презентация и скрипты со встречи сообщества по SharePoint и Office 365

PowerShell DSC. SharePoint

PowerShell DSC. SharePoint

PowerShell DSC. Сертификат для шифрования пароля

PowerShell DSC. Сертификат для шифрования пароля

PowerShell DSC. Учетные записи

PowerShell DSC. Учетные записи

Встреча сообщества по SharePoint и Office 365

Встреча сообщества по SharePoint и Office 365

SharePoint 2016. QR-code

SharePoint 2016. QR-code

Возможности SharePoint 2010/2013/2016

Возможности SharePoint 2010/2013/2016

Gmail IIS SMTP relay

Gmail IIS SMTP relay

SharePoint 2016. Извещения мозаикой

SharePoint 2016. Извещения мозаикой

Сертификация SharePoint по-новому

Сертификация SharePoint по-новому

SharePoint. Получение списка сайтов

SharePoint. Получение списка сайтов

Планирование фермы SharePoint

Планирование фермы SharePoint

Обзор SharePoint Education. Часть 3

Обзор SharePoint Education. Часть 3

SharePoint Excel Services. Отображение диаграммы на странице

SharePoint Excel Services. Отображение диаграммы на странице

SharePoint 2016 Release Candidate

SharePoint 2016 Release Candidate

Обзор SharePoint Education. Часть 2

Обзор SharePoint Education. Часть 2

Обзор SharePoint Education. Часть 1

Обзор SharePoint Education. Часть 1

SharePoint 2013 Образование. Установка и настройка

SharePoint 2013 Образование. Установка и настройка

SharePoint 2016 IT Preview

SharePoint 2016 IT Preview

SharePoint и SMS. Часть 2. Регистрация OMS-сервиса

SharePoint и SMS. Часть 2. Регистрация OMS-сервиса

SharePoint и SMS. Часть 1. Создание OMS веб-сервиса

SharePoint и SMS. Часть 1. Создание OMS веб-сервиса

SharePoint Day: 14 декабря, Москва

SharePoint Day: 14 декабря, Москва

RuSUG 17.10.2013. Презентация с моего доклада о новом поиске в SharePoint 2013

RuSUG 17.10.2013. Презентация с моего доклада о новом поиске в SharePoint 2013

SharePoint 2013 Ribbon API. Версии 14.3 и 15.4

SharePoint 2013 Ribbon API. Версии 14.3 и 15.4

Встреча RuSUG 17-го октября

Встреча RuSUG 17-го октября

SharePoint 2013. Служба ServiceDesk за 8 часов либо правильный проект

SharePoint 2013. Служба ServiceDesk за 8 часов либо правильный проект

SharePoint 2010/2013. Локализация данных

SharePoint 2010/2013. Локализация данных

Список возможностей SharePoint 2013

Список возможностей SharePoint 2013

SharePoint 2013. Типы полей

SharePoint 2013. Типы полей

SharePoint 2013 Enterprise Search. Часть 2. Создание обработчика контента

SharePoint 2013 Enterprise Search. Часть 2. Создание обработчика контента

SharePoint 2013 Enterprise Search. Часть 1. Логическая архитектура

SharePoint 2013 Enterprise Search. Часть 1. Логическая архитектура

SharePoint Ribbon. Использование ColorPicker'а

SharePoint Ribbon. Использование ColorPicker'а

Разработка для SharePoint. Как это было и как это будет

Разработка для SharePoint. Как это было и как это будет

SharePoint. История социализма за 10 лет

SharePoint. История социализма за 10 лет

SharePoint 2013 Preview

SharePoint 2013 Preview

Использование штрихкодов в SharePoint 2010

Использование штрихкодов в SharePoint 2010

Unable to locate the xml-definition for FieldName

Unable to locate the xml-definition for FieldName

SharePoint 2010. Апрельский накопительный пакет обновлений

SharePoint 2010. Апрельский накопительный пакет обновлений

Не удалось найти XML-файл в указанном расположении

Не удалось найти XML-файл в указанном расположении

Служба синхронизации профилей пользователей. Ошибки

Служба синхронизации профилей пользователей. Ошибки

Делаем сайт на SharePoint 2010. Построение иерархии страниц

Делаем сайт на SharePoint 2010. Построение иерархии страниц

Делаем сайт на SharePoint 2010. Брендинг Wiki-страниц

Делаем сайт на SharePoint 2010. Брендинг Wiki-страниц

Делаем сайт на SharePoint 2010. Оптимизация

Делаем сайт на SharePoint 2010. Оптимизация

Делаем сайт на SharePoint 2010. Брендинг

Делаем сайт на SharePoint 2010. Брендинг

Обработка большого количества элементов в SharePoint

Обработка большого количества элементов в SharePoint

Получение уникальных значений поля списка

Получение уникальных значений поля списка

DeskWork 5. Функциональность (продолжение)

DeskWork 5. Функциональность (продолжение)

Сокрытие информации о пользователе создавшем/изменившем элемент

Сокрытие информации о пользователе создавшем/изменившем элемент

Error : Code blocks are not allowed in this file

Error : Code blocks are not allowed in this file

SharePoint Client Object Model. Управляемый код

SharePoint Client Object Model. Управляемый код

Использование контрола HtmlEditor. Часть 3

Использование контрола HtmlEditor. Часть 3

SharePoint 15 SDK

SharePoint 15 SDK

PeopleEditor и Internet Explorer 9

PeopleEditor и Internet Explorer 9

Использование контрола HtmlEditor. Часть 2

Использование контрола HtmlEditor. Часть 2

Использование контрола HtmlEditor. Часть 1

Использование контрола HtmlEditor. Часть 1

Пропадающий контрол выбора представления списка

Пропадающий контрол выбора представления списка

Развертывание библиотеки документов с файлами

Развертывание библиотеки документов с файлами

Отключенные учетные записи и PeoplePicker

Отключенные учетные записи и PeoplePicker

Пропадающий TextBox в Telerik Reporting

Пропадающий TextBox в Telerik Reporting

Длительные операции в SharePoint. Request timed out

Длительные операции в SharePoint. Request timed out

Длительные операции в SharePoint. Изнутри

Длительные операции в SharePoint. Изнутри

Длительные операции в SharePoint. Снаружи

Длительные операции в SharePoint. Снаружи

DeskWork. Версия 5.1

DeskWork. Версия 5.1

DeskWork 5. Часть 2. Функциональность

DeskWork 5. Часть 2. Функциональность

DeskWork 5. Часть 1. Установка

DeskWork 5. Часть 1. Установка

SharePoint 2010. Random ListItem

SharePoint 2010. Random ListItem

Custom ListDefinition. Отключаем диалоги

Custom ListDefinition. Отключаем диалоги

SharePoint 2010 UpdatePanel. Request Notification

SharePoint 2010 UpdatePanel. Request Notification

Получение размера вложений SPListItem'а

Получение размера вложений SPListItem'а

SharePoint 2010. Переопределение форм типа содержимого

SharePoint 2010. Переопределение форм типа содержимого

SharePoint 2007/2010. Привязываем EventReceiver к типу содержимого

SharePoint 2007/2010. Привязываем EventReceiver к типу содержимого

Изменяем appSettings в config-файле

Изменяем appSettings в config-файле

SharePoint 2010. Добавляем сборку в пакет

SharePoint 2010. Добавляем сборку в пакет

SharePoint 2007/2010. The security validation for this form is invalid

SharePoint 2007/2010. The security validation for this form is invalid

SharePoint 2010. JavaScript IntelliSence

SharePoint 2010. JavaScript IntelliSence

SharePoint 2010. Локализация SiteDefinition

SharePoint 2010. Локализация SiteDefinition

SharePoint 2007. Получение данных из нескольких списков и узлов

SharePoint 2007. Получение данных из нескольких списков и узлов

SharePoint 2007. Максимальное/минимальное значение поля в списке

SharePoint 2007. Максимальное/минимальное значение поля в списке

SharePoint 2007. Свой контрол на панели свойств веб-парта

SharePoint 2007. Свой контрол на панели свойств веб-парта

SharePoint 2007. База данных содержимого

SharePoint 2007. База данных содержимого

SharePoint 2007. Проверка на наличие элемента в списке

SharePoint 2007. Проверка на наличие элемента в списке