Windows Ribbon в .NET-приложениях (ч.3)
В предыдущей статье мы научились создавать на ленте меню приложения с несколькими видами кнопок, попутно рассмотрев, для чего каждый из "необычных" видов кнопок используется. Кроме того, было сделано замечание касаемо метода DestroyFramework ленты: мы рассмотрели случай, когда его использование в сочетании со стандартной функцией закрытия формы WinForms вызывает ошибку, и выяснили, как этой ошибки можно избежать.
Сегодня мы рассмотрим ещё несколько элементов управления ленты, как-то: вкладки (Tabs) с группами (Groups), кнопка справки (HelpButton), счётчик (Spinner) и раскрывающийся (или выпадающий) список (ComboBox).
Итак, приступим.
Вкладки, группы и кнопка справки
Результатом данной части статьи будет очередное приложение-образец с именем "04-TabGroupHelp". Выглядит оно следующим образом:
Кнопки, кнопки, кнопки
Так что же есть вкладки? Это всего лишь контейнеры для других элементов управления. В этом примере мы будем использовать только кнопки. Я рассмотрю другие типы контролов в следующих статьях.
Каждая вкладка может содержать несколько групп, которые являются просто логическим разделением элементов на вкладке, в данной статье — кнопок...
Что такое кнопка справки? Ещё одна кнопка. Из некоторых соображений у неё есть своё особое место и заранее заданный значок (см. на правую сторону изображения).
Использование вкладок и групп
Секция команд разметки ленты остаётся всё той же — просто список элементов, сопоставляющих обозначения, используемые программистом, и идентификаторы, используемые фреймворком ленты. А также некоторые строковые ресурсы и точечные рисунки.
Как всегда, всё интересное находится в секции представлений разметки:
<Application.Views>
<Ribbon>
<Ribbon.Tabs>
<Tab CommandName="cmdTabMain">
<!-- страшная часть -->
<Tab.ScalingPolicy>
<ScalingPolicy>
<ScalingPolicy.IdealSizes>
<Scale Group="cmdGroupFileActions" Size="Large" />
<Scale Group="cmdGroupExit" Size="Large" />
</ScalingPolicy.IdealSizes>
<Scale Group="cmdGroupFileActions" Size="Medium" />
</ScalingPolicy>
</Tab.ScalingPolicy>
<!-- полезная часть -->
<Group CommandName="cmdGroupFileActions" SizeDefinition="ThreeButtons">
<Button CommandName="cmdButtonNew" />
<Button CommandName="cmdButtonOpen" />
<Button CommandName="cmdButtonSave" />
</Group>
<Group CommandName="cmdGroupExit" SizeDefinition="OneButton">
<Button CommandName="cmdButtonExit" />
</Group>
</Tab>
<Tab CommandName ="cmdTabDrop">
<Group CommandName="cmdGroupDrop" SizeDefinition="ThreeButtons">
<Button CommandName="cmdButtonDropA" />
<Button CommandName="cmdButtonDropB" />
<Button CommandName="cmdButtonDropC" />
</Group>
</Tab>
</Ribbon.Tabs>
</Ribbon>
</Application.Views>
iews>[/code]
В этой разметке я назначил две вкладки. На первой вкладке расположены две группы, на второй — одна. Я обозначил важные части разметки первой вкладки. К сожалению, в силу особенностей определения схемы (англ. schema definition — прим. переводчика) ленты, "страшная" часть должна располагаться перед "полезной".
"Полезная" часть:
Всего лишь простое назначение групп на вкладке и элементов управления внутри каждой группы. Единственная интересная вещь — это атрибут SizeDefinition в тэге Group. Это определение расположения контролов в группе. Вы можете описать собственные варианты расположения или использовать уже имеющиеся, которых обычно бывает вполне достаточно. Полный список (с удобными иллюстрациями) можно посмотреть в статье "
"Страшная" часть:
Чтобы понять эту часть, нужно знать, что одной из функций фреймворка ленты является возможность перераспределения ваших контролов на ленте в соответствии с имеющимся пространством. В основном лента обрабатывает это автоматически, но ей необходимо дать "подсказку", как следует распределять элементы, когда форма приложения становится всё меньше и меньше. Поэтому в "страшной" части мы сначала задаём идеальный размер для каждой группы. Размер может принимать одно из четырёх значений: Large (большой), Medium (средний), Small (маленький) и Popup (всплывающий). "Popup" означает, что вся группа должна сжиматься в один значок и "всплывать" при щелчке по нему.
После назначения идеального размера для группы, вы можете указать порядок уменьшения масштаба, то есть какая группа должна масштабироваться первой. Таким образом, можно сделать так, чтобы наиболее важные контролы приложения были видны лучше, чем менее важные.
Код для работы с этими кнопками такой же, как в предыдущей статье. Просто обрабатывайте событие OnExecute соответствующих кнопок.
Использование кнопки справки
Чтобы использовать кнопку справки, просто добавьте следующие строки в секцию представлений разметки ленты:
[code]<Application.Views>
<Ribbon>
<Ribbon.HelpButton>
<HelpButton CommandName="cmdHelp" />
</Ribbon.HelpButton>
<Ribbon.Tabs>
...
</Ribbon.Tabs>
</Ribbon>
</Application.Views>[/code]
Элемент управления "счётчик"
Элемент управления "счётчик" (Spinner) — контрол, который содержит десятичное значение (как тип double, только с более высоким разрешением). Элемент состоит из поля для редактирования и двух кнопок, для увеличения и уменьшения. Давайте попробуем его в действии:
Свойства счётчика
Каждый элемент управления ленты обладает свойствами, которые определяют его внешний вид и поведение. Вот краткое перечисление свойств счётчика, разделённое на логические группы:
Свойства счётчика, относящиеся к его значению
- Decimal Value — Текущее десятичное значение счётчика.
Идентификатор свойства: UI_PKEY_DecimalValue - Increment — Размер шага при нажатии на кнопки увеличения / уменьшения значения.
Идентификатор свойства: UI_PKEY_Increment - Max Value — Максимальное значение, которое можно задать на счётчике.
Идентификатор свойства: UI_PKEY_MaxValue - Min Value — Минимальное значение, которое можно задать на счётчике.
Идентификатор свойства: UI_PKEY_MinValue
Замечание: Когда вы используете десятичные значения в Ribbon Framework, вы должны также использовать реализацию PropVariant, поддерживающую десятичные значения. Подробней об этом написано здесь:
Свойства счётчика, относящиеся к его оформлению
- Decimal Places — Количество цифр после запятой.
Идентификатор свойства: UI_PKEY_DecimalPlaces - Format String — Единицы измерения значения. На предыдущем изображении это "м" — метры.
Идентификатор свойства: UI_PKEY_FormatString - Representative String — Строка, представляющая общее значение для счётчика. Используется для вычисления ширины счётчика, поэтому следует задавать здесь самую длинную строку, которая будет выводиться. Заметьте, что это не обязательно должно быть действительное значение, можно задать что-нибудь вроде: "XXXXXXXX".
Идентификатор свойства: UI_PKEY_RepresentativeString
Общие параметры оформления
- Keytip — Клавиатурный ускоритель ("горячая клавиша") для данной команды в фреймворке ленты (показывается при нажатии ALT в приложении с лентой).
Идентификатор свойства: UI_PKEY_Keytip - Label — Метка для данной команды. Обычно появляется рядом с назначенным элементом управления.
Идентификатор свойства: UI_PKEY_Label - Tooltip Title — Заголовок всплывающей подсказки для данной команды.
Идентификатор свойства: UI_PKEY_TooltipTitle - Tooltip Description — Текст всплывающей подсказки для данной команды.
Идентификатор свойства: UI_PKEY_TooltipDescription - Enabled — Флаг, показывающий, включён данный элемент управления или нет.
Идентификатор свойства: UI_PKEY_Enabled
Свойства изображений
- Large Image — Большое изображение для данной команды.
Идентификатор свойства: UI_PKEY_LargeImage - Small Image — Маленькое изображение для данной команды.
Идентификатор свойства: UI_PKEY_SmallImage - Large High Contrast Image — Большое изображение с высоким контрастом для данной команды.
Идентификатор свойства: UI_PKEY_LargeHighContrastImage - Small High Contrast Image — Маленькое изображение с высоким контрастом для данной команды.
Идентификатор свойства: UI_PKEY_SmallHighContrastImage
Использование счётчика — разметка ленты
Как всегда, команда должна быть определена:
[code]<Command Name="cmdSpinner"
Id="1018"
LabelTitle="Мой счётчик">
</Command>[/code]
Секция представлений тоже простая:
[code]<Application.Views>
<Ribbon>
<Ribbon.Tabs>
<Tab>
<Group>
<Spinner CommandName="cmdSpinner" />
</Group>
</Tab>
</Ribbon.Tabs>
</Ribbon>
</Application.Views>[/code]
Использование счётчика — код
Чтобы помочь нам управлять счётчиком, я создал вспомогательный класс, в котором выполняется вся работа, затрагивающая фреймворк ленты. Чтобы использовать его, создайте экземпляр RibbonSpinner, передав конструктору ссылку на экземпляр класса Ribbon и ID команды счётчика:
[code]private Ribbon _ribbon;
private RibbonSpinner _spinner;
public Form1()
{
InitializeComponent();
_ribbon = new Ribbon();
_spinner = new RibbonSpinner(_ribbon, (uint)RibbonMarkupCommands.cmdSpinner);
}[/code]
Теперь вы можете легко управлять свойствами счётчика, задавая их для экземпляра _spinner, например:
[code]private void InitSpinner()
{
_spinner.DecimalPlaces = 2;
_spinner.DecimalValue = 1.8M;
_spinner.TooltipTitle = "Высота";
_spinner.TooltipDescription = "Введите высоту в метрах.";
_spinner.MaxValue = 2.5M;
_spinner.MinValue = 0;
_spinner.Increment = 0.01M;
_spinner.FormatString = " м";
_spinner.RepresentativeString = "2.50 м";
_spinner.Label = "Высота:";
}[/code]
Использование элемента управления "счётчик" показано в приложении-образце "05-Spinner".
От переводчика: в заключении статьи смотрите очень важное замечание касательно счётчика.
Элемент управления "выпадающий список"
Элемент управления "выпадающий (или раскрывающийся) список" (ComboBox) ленты — по сути обычный контрол ComboBox, который мы все любим, но с дополнительной возможностью разделения элементов по категориям. Категория не является элементом и не может быть выбрана из списка. Она используется только для упорядочения элементов.
Свойства выпадающего списка, относящиеся к его значению
- Items Source — Список элементов ComboBox. Он реализует интерфейс IUICollection, каждый элемент которого относится к типу: IUISimplePropertySet. Об этом будет рассказано чуть позже.
Идентификатор свойства: UI_PKEY_ItemsSource - Categories — Список категорий. Также реализует IUICollection элементов IUISimplePropertySet.
Идентификатор свойства: UI_PKEY_Categories - Selected Item — Индекс выбранного элемента в выпадающем списке. Если ничего не выбрано, возвращает UI_Collection_InvalidIndex, то есть, грубо говоря, -1.
Идентификатор свойства: UI_PKEY_SelectedItem - String Value — Текущая строка в ComboBox. Это может быть строка, не являющаяся одним из элементов выпадающего списка, если его свойству IsEditable присвоено значение "true".
Идентификатор свойства: UI_PKEY_StringValue
Свойства выпадающего списка, относящиеся к его оформлению
- Representative String — Строка, представляющая общее значение для ComboBox. Используется для вычисления ширины выпадающего списка, поэтому следует задавать здесь самую длинную строку, которая будет выводиться. Заметьте, что это не обязательно должно быть действительное значение, можно задать что-нибудь вроде: "XXXXXXXX".
Идентификатор свойства: UI_PKEY_RepresentativeString
Использование выпадающего списка — разметка ленты
Как всегда, команда должна быть определена:
[code]<Command Name="cmdComboBox2" Id="1019" />[/code]
Секция представлений:
[code]<Application.Views>
<Ribbon>
<Ribbon.Tabs>
<Tab>
<Group>
<ComboBox CommandName="cmdComboBox2"
IsAutoCompleteEnabled="true"
IsEditable="true"
ResizeType="VerticalResize" />
</Group>
</Tab>
</Ribbon.Tabs>
</Ribbon>
</Application.Views>[/code]
Атрибуты ComboBox:
- CommandName — Имя команды, привязанной к данному выпадающему списку.
- IsAutoCompleteEnabled — Флаг, показывающий, дополнять ли слова, когда вы пишете.
- IsEditable — Флаг, показывающий, возможно ли свободное редактирование текста в ComboBox.
- ResizeType — Возможность изменения размера ComboBox. Может принимать значения NoResize или VerticalResize.
Использование выпадающего списка — код
По аналогии с элементом управления "счётчик", я создал вспомогательный класс для взаимодействия между выпадающим списком и фреймворком ленты. Чтобы использовать ComboBox, создайте экземпляр RibbonComboBox, передав конструктору ссылку на экземпляр класса Ribbon и ID команды списка:
[code]private Ribbon _ribbon;
private RibbonComboBox _comboBox2;
public Form1()
{
InitializeComponent();
_ribbon = new Ribbon();
_comboBox2 = new RibbonComboBox(_ribbon, (uint)RibbonMarkupCommands.cmdComboBox2);
_comboBox2.RepresentativeString = "XXXXXXXXXXX";
}[/code]
Замечание: Мы задаём свойство RepresentativeString ПЕРЕД инициализацией фреймворка ленты. Это делается в силу того, что по некоторым причинам фреймворк считывает это свойство только однажды, когда лента инициализируется. Это означает, что, если вы измените его после инициализации, результата не будет, поскольку фреймворк его более не считывает. Кстати говоря, согласно
В следующем куске кода показано, как использовать другой вспомогательный класс, называющийся GalleryItemPropertySet. Этот класс предоставляет контейнер для свойств отдельного элемента в IUICollection.
Добавление категорий и элементов в выпадающий список производится таким образом:
[code]private void Form1_Load(object sender, EventArgs e)
{
_ribbon.InitFramework(this);
// задаём метку combobox2
_comboBox2.Label = "Расширенный список";
// задаём категории _comboBox2
IUICollection categories2 = _comboBox2.Categories;
categories2.Clear();
categories2.Add(new GalleryItemPropertySet() { Label="Категория 1", CategoryID=1 });
categories2.Add(new GalleryItemPropertySet() { Label="Категория 2", CategoryID=2 });
// задаём элементы _comboBox2
IUICollection itemsSource2 = _comboBox2.ItemsSource;
itemsSource2.Clear();
itemsSource2.Add(new GalleryItemPropertySet() { Label="Метка 1", CategoryID=1 });
itemsSource2.Add(new GalleryItemPropertySet() { Label="Метка 2", CategoryID=1 });
itemsSource2.Add(new GalleryItemPropertySet() { Label="Метка 3", CategoryID=2 });
}[/code]
Замечание: Добавление элементов и категорий возможно только ПОСЛЕ того, как фреймворк ленты был инициализирован.
События IUICollection
Объекты, реализующие интерфейс IUICollection, обычно посылают событие OnChanged, вызываемое в случае, если коллекция была изменена: вставкой элемента, удалением элемента, заменой элемента, сбросом коллекции.
Это событие посылается с помощью стандартного механизма событий COM, а именно: IConnectionPointContainer, IConnectionPoint и Advise().
Чтобы помочь пользователю обойти все эти вещи, я создал класс UICollectionChangedEvent, который привязывается к соответствующему интерфейсу IUICollection и посылает событие OnChanged как обычное .NET-событие.
Ниже приведён пример его использования:
[code]private RegisterEvent()
{
_uiCollectionChangedEvent = new UICollectionChangedEvent();
_uiCollectionChangedEvent.Attach(_comboBox1.ItemsSource);
_uiCollectionChangedEvent.OnChanged +=
new UICollectionChangedEvent.OnChangedEventHandler(_ChangedEvent_OnChanged);
}
[/code]
[code]void _ChangedEvent_OnChanged(UI_CollectionChange action,
uint oldIndex, object oldItem,
uint newIndex, object newItem)
{
MessageBox.Show("Получено событие OnChanged. Действие = " + action.ToString());
}[/code]
Замечание: Для ComboBox события OnChanged нет. Только для интерфейса IUICollection, который полностью отличается от контрола. Сам выпадающий список имеет 3 события, Execute, Preview и CancelPreview. Событие Execute можно использовать как событие "изменения выбора". Об этом будет рассказано в будущих статьях.
Использование элемента управления "выпадающий список" показано в приложении-образце "06-ComboBox".
Заключение
Имеется крайне важное замечание, касающееся элемента управления "счётчик" (Spinner). Один из пользователей
Арик довольно оперативно отреагировал на сообщение об ошибке и
Также хотелось бы упомянуть COM-структуру PropVariant, о которой было сказано в замечании к свойствам элемента управления "счётчик". Её подходящая реализация уже включена Ариком в проект его библиотеки, поэтому беспокоиться об этом не стоит.
На этом пока всё.
В следующей статье мы рассмотрим, как можно изменять цвет ленты, а также поговорим об изображениях, используемых на ленте. Кроме этого, возможно, уже в следующей статье будет рассказано о различных видах галерей на ленте Windows.
Август 2010
Комментарии
Хорошая статья. Только не могу понять почему в VS до сих пор нет стандартного визуального компонента что-бы просто взять и перетянуть.
Sm1le, есть, но он предназначен для MFC-приложений. Читайте
Исходные сообщения в блоге Арика Познански, переведённые в этой статье:
Sgt.Riggs , mfc это хорошо, но я с++ давно забросил, так что надеюсь когда нибудь компонент появится)
Sm1le, может и появится, но пока нет. А нынешний Windows Ribbon - это COM-элемент, так что в идеале им управлять надо нативными функциями, то бишь нужен C++. Потому Арик свой враппер и написал, который, кстати, прекрасно работает, а Арик очень оперативно реагирует на сообщения о возможных ошибках, если их кто-то находит (сам с ним по поводу одной недоработки общался зимой, очень приятный в общении человек, кстати). А если учесть, что он сотрудник Microsoft Israel... В общем, по сути этот враппер и есть официальная реализация Ribbon для .NET Один минус - отсутствие визуального редактора ленты. Я задолбался в своём приложении писать разметку :-D Но в не-MFC-шных C++-приложениях всё то же самое, так что... Ну и кроме того, есть сторонние визуальные редакторы ленты, создающие полный код разметки.
SVRC, отлично, спасибо, что сообщили! Коллекция лент пополнилась ещё одной реализацией.
По теме
- Видео-курсы от MS: Разработка приложений виртуальной и расширенной реальности на платформе Microsoft
- ECMA JavaScript 6: Объекты
- Как просто создать приложение для iPhone
- Разработка приложений под Windows Phone 8
- Индексированное хранилище, часть 2
- Индексированное хранилище, часть 1
- Начала Metro-программирования: создание настраиваемых приложений (ч.2)
- Начала Metro-программирования: создание настраиваемых приложений (ч.1)
- Начала Metro-программирования: создание компонентов WinRT (ч.3)
- Начала Metro-программирования: создание компонентов WinRT (ч.2)