Windows Ribbon в .NET-приложениях (ч.1)

Автор: Topol Суббота, Май 5th, 2012 Нет комментариев

Рубрика: Операционные системы

В предыдущей статье я постарался кратко описать то, с чем же мы будем иметь дело на протяжении всей настоящей серии статей, но не стал давать какого-либо конкретного материала касаемо самого предмета. В сегодняшней, по сути, первой статье серии я уже перейду непосредственно к переводу сообщений Арика Познански.

В данной статье мы немного ближе познакомимся с тем, что же всё-таки представляет собой элемент управления Ribbon, а также узнаем краткую историю его развития. Затем мы попытаемся понять некоторые технические детали написания Ариком его враппера, и, наконец, перейдём непосредственно к созданию первого приложения с лентой.

В конце предыдущей статьи я указал список необходимого ПО, которое понадобится при разработке приложений WinForms с поддержкой Windows Ribbon. Здесь и далее я буду считать, что всё это ПО у нас уже имеется и готово к использованию.

Итак, начнём.

История
Перед тем, как мы начнём программировать, давайте немного поговорим непосредственно о предмете.

Определение

     (с MSDN): «Windows Ribbon (Ribbon) Framework — это система представления команд с широкими возможностями, являющаяся современной альтернативой меню, панелям инструментов и области задач традиционных Windows-приложений.»

В Office 2007 компания Майкрософт представила новый способ организации пользовательского интерфейса в приложении. Проблемой старого UI было то, что он был недостаточно гибким для представления всех возможностей Office. (На самом деле, люди просили добавить функции, которые уже имелись, но были «упрятаны» далеко в меню…)


Лента Microsoft Word 2007

Когда оказалось, что лента Office 2007 стала успешной, многие компании, занимающиеся разработкой UI, реализовали свои варианты лент для использования в приложениях. Ну а когда в Майкрософт осознали, что у них получилось нечто хорошее, они решили вывести ленту «в широкие массы».

Они выпустили 3 (!) версии ленты:

      [

 

  • MFC-версия, доступна в Visual Studio 2008 SP1 (и 2010 — прим. переводчика), для использования в нативных MFC-приложениях
  • WPF-версия, доступна в WPF Toolkit для .Net 3.5 SP1, для использования в управляемых WPF-приложениях
  • Windows Ribbon, доступна в Windows 7 как COM-объект [и в последующем обновлении для Vista], для использования в нативных win32-приложениях.

Ну, а что насчёт разработчиков управляемых WinForms-приложений? Они должны использовать третью, основанную на COM, версию. Поэтому цель этих статей — предоставить вам работающие примеры использования Windows Ribbon в приложениях WinForms.

Зачем использовать Windows Ribbon?
Заметьте: вопрос, на который я собираюсь ответить, звучит как «Зачем использовать ЭТОТ элемент управления Ribbon?», а не «Зачем ВООБЩЕ использовать элемент управления Ribbon?» Почему бы не использовать другие ленты? Существуют дюжины сторонних контролов; некоторые из них бесплатны.

Основная причина использования Windows Ribbon Framework — он разработан Майкрософт. Это означает:

  • Поскольку он оригинальный, он обладает ВСЕМИ возможностями ленты, в отличие от других бесплатных или коммерческих Ribbon-контролов, в которых всегда найдутся «не реализованные» моменты.
  • Он обладает ПОЛНОЙ поддержкой и интеграцией с интерфейсом Windows 7 и специальными возможностями. Просто представьте поддержку сенсорных экранов или совместимость с более высокими разрешениями (DPI) экрана.

Создание .NET-врапперов
Первое, что необходимо было сделать, чтобы использовать Windows Ribbon в .NET-приложениях, — конвертировать определения C++ / COM в C#.

К ленте относятся следующие файлы: UIRibbon.idl, UIRibbonKeydef.h и UIRibbonPropertyHelpers.h. Заметьте, что файл UIRibbon.h не интересен, поскольку он автоматически генерируется из UIRibbon.idl компилятором MIDL (англ. Microsoft Interface Definition Language — «язык описания интерфейсов Майкрософт» — прим. переводчика). Все эти файлы устанавливаются вместе с Windows 7 SDK.

Я не буду обсуждать подробности конвертации, поскольку это весьма механический процесс — просто поменять каждый тип C++ и преобразовать его в соответствующий .NET-эквивалент. Если вам интересны эти детали, на .NET interoperability имеется просто бесконечное количество информации.

Согласно условностям Windows API Code Pack, файл UIRibbon.idl был конвертирован в 4 различных файла:

  • RibbonProperties.cs — содержит описание свойств Ribbon
  • RibbonCOMGuids.cs — содержит относящиеся к Ribbon GUID’ы (англ. Globally Unique Identifier — «глобальный уникальный идентификатор» — прим. переводчика)
  • RibbonCOMInterfaces.cs — содержит описание интерфейсов Ribbon
  • RibbonCOMClasses.cs — содержит описание классов Ribbon

Эти файлы — преобразованные мной [Ариком] COM-интерфейсы и типы, используемые Windows Ribbon Framework. Эти файлы могут изменяться в процессе развития проекта, поскольку я наверняка допустил какие-то ошибки в преобразованиях и узнаю об этом, когда попытаюсь использовать какую-либо функцию.

(на момент написания этих статей библиотека Windows Ribbon for WinForms уже довольно длительное время находится в стадии релиза, поэтому если Ариком и будут исправляться какие-либо ошибки, то лишь незначительные. — прим. переводчика).

Как работает Windows Ribbon Framework?
Более подробно об этом написано на MSDN, я рекомендую это прочитать. Здесь я дам лишь краткое описание, чтобы мы просто друг друга понимали.

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

1. Спроектировать оформление ленты, используя разметку вида XAML.
2. Скомпилировать эту XAML-разметку с помощью Microsoft Ribbon Markup Compiler (компилятора разметки ленты), входящего в состав Windows 7 SDK.
3. Сделать бинарный вывод компилятора разметки (неуправляемым) ресурсом вашего приложения.
4. Во время загрузки приложения выполнить CoCreateInstance для класса UIRibbonFramework, который реализует интерфейсIUIFramework.
5. Вызвать framework.Initialize и передать ему ссылку на реализацию интерфейса IUIApplication вместе с HWND (англ. window handle — «описатель окна» — прим. переводчика) окна вашего приложения. Интерфейс IUIApplication отправляет обратный вызов фреймворку ленты, когда ему нужен описатель команды для её обработки (команды представлены кнопками, комбо-боксами и другими стандартными элементами управления).
6. Вызвать framework.LoadUI, который загружает предварительно скомпилированный ресурс и показывает ленту.

Что я сделал? 
Чтобы упростить использование ленты в .NET-приложениях, мы создадим класс, который будет использоваться как фасад для Windows Ribbon Framework. Этот класс, названный Ribbon, будет заниматься инициализацией и связью с Windows Ribbon Framework.

Класс Ribbon предоставит реализацию IUIApplication и будет обрабатывать все детали COM. Информация, которую он не сможет отправить сам, будет предоставляться вашей реализацией интерфейса IRibbonForm (который придумал я, поэтому не пытайтесь его где-либо отыскать). Идея состоит в том, чтобы ваше приложение предоставляло минимальные подробности, необходимые для работы ленты.

На данный момент IRibbonForm описан примерно так:

Код:
/// <summary>
/// Интерфейс IRibbonForm должен быть реализован главной формой, которой требуется лента
/// </summary>
public interface IRibbonForm : IUICommandHandler
{
/// <summary>
/// Получение описателя окна главной формы
/// </summary>
IntPtr WindowHandle { get; }

/// <summary>
/// Вызывается, когда изменяется высота ленты,
/// позволяя форме перераспределить свои контролы так, чтобы лента их не перекрыла.
/// </summary>
/// <param name=»newHeight»>новая высота</param>
void RibbonHeightUpdated(int newHeight);
}

Свойство WindowHandle используется для передачи описателя родительского окна фреймворку ленты.

Функция RibbonHeightUpdated используется, чтобы предупредить ваше приложение, что высота ленты изменилась. Поскольку высота ленты может динамически меняться (например, если вы измените размер окна до минимального, лента исчезнет), вам понадобится это предупреждение, чтобы соответствующим образом перераспределить элементы управления на форме (чтобы лента их не перекрыла).

Класс Ribbon на данный момент имеет 2 метода:

  • InitFramework — получает вашу реализацию интерфейса IRibbonForm и имя ресурса, который будет использован для загрузки конфигурации ленты.
  • DestroyFramework — код очистки, освобождает ресурсы Windows Ribbon Framework.

Эти методы должны быть вызваны, когда главная форма приложения загружается и закрывается соответственно.

Первое WinForms-приложение с лентой
Итак, давайте посмотрим, как использовать класс Ribbon для добавления поддержки в пустое WinForms-приложение. Результатом будет приложение-образец «01-AddingRibbonSupport».

Шаг 1 — Сослаться на Windows Ribbon for WinForms
Создайте новое WinForms-приложение на C# и добавьте в решение проект нашей библиотеки, Ribbon.csproj, а в проект вашего приложения — ссылку на него.

Также добавьте к главной форме (form1.cs) следующие строки:

Код:
using RibbonLib;
using RibbonLib.Interop;

public partial class Form1 : Form, IRibbonForm
{
private Ribbon _ribbon = new Ribbon();

Шаг 2 — Добавить XML-файл разметки ленты
Добавьте к проекту пустой файл с именем RibbonMarkup.xml. Вставьте в файл следующий текст:

Код:
<?xml version=’1.0′ encoding=’utf-8′?>
<Application xmlns=’http://schemas.microsoft.com/windows/2009/Ribbon’>
<Application.Commands>
</Application.Commands>

<Application.Views>
<Ribbon>
</Ribbon>
</Application.Views>
</Application>

Щёлкните правой кнопкой мыши в окне редактирования RibbonMarkup.xml и нажмите «Свойства», затем задайте свойство «Схемы» равным: C:\Program Files\Microsoft SDKs\Windows\v7.1\Bin\UICC.xsd. Это [визуально] поможет вам в будущем при редактировании файла разметки ленты (попробуйте нажать Ctrl+Пробел в XML-редакторе, чтобы увидеть синтаксис разметки ленты).

Шаг 3 — Указать компилятору UI скомпилировать разметку в процессе построения
Войдите в: Свойства проекта -> События построения -> Командная строка события перед построением. Добавьте следующие 3 строки:

«C:\Program Files\Microsoft SDKs\Windows\v7.1\Bin\UICC.exe» «$(ProjectDir)RibbonMarkup.xml» «$(ProjectDir)RibbonMarkup.bml» /res:»$(ProjectDir)RibbonMarkup.rc»

«C:\Program Files\Microsoft SDKs\Windows\v7.1\Bin\rc.exe» /v «$(ProjectDir)RibbonMarkup.rc»

cmd /c «(«$(DevEnvDir)..\..\VC\bin\vcvars32.bat») && («$(DevEnvDir)..\..\VC\bin\link.exe» /VERBOSE /NOENTRY /DLL /OUT:»$(ProjectDir)$(OutDir)$(TargetName).ribbon.dll» «$(ProjectDir)RibbonMarkup.res»)»

Пояснение: первая строка компилирует файл разметки ленты в сжатый бинарный формат, сопровождаемый маленьким RC-файлом, описывающим его.
Вторая строка создаёт нативный файл ресурса win32, который будет присоединён к нативным ресурсам проекта. Третья строка создаёт DLL-библиотеку с ресурсами из нативного файла ресурса win32.

Теперь скомпилируйте проект, чтобы ввести события перед построением.

Шаг 4 — Реализовать IRibbonForm
Чтобы ваша главная форма реализовывала интерфейс IRibbonForm, описанный в Ribbon.dll, выполните следующие инструкции:

• Фреймворку ленты необходим описатель окна главной формы для инициализации, отсюда:

Код:
public IntPtr WindowHandle
{
get
{
return this.Handle;
}
}

• Лента частично перекроет вашу форму, если вы не напишете некоторый код, который будет перераспределять ваши контролы согласно текущей высоте ленты. Простой способ это сделать — добавить элемент управления SplitContainer на главную форму и задать ему следующие свойства (лучше задавать их в визуальном редакторе, а не в коде):

Код:
this.splitContainer1.Dock = System.Windows.Forms.DockStyle.Fill;
this.splitContainer1.FixedPanel = System.Windows.Forms.FixedPanel.Panel1;
this.splitContainer1.IsSplitterFixed = true;
this.splitContainer1.Orientation = System.Windows.Forms.Orientation.Horizontal;
this.splitContainer1.SplitterWidth = 1;

Теперь все, что вам нужно сделать, это расположить контролы вашей формы внутри panel2 SplitContainer’а и обновлять высоту panel1, когда меняется высота ленты (panel1 является «вместилищем» для ленты). SplitContainer будет автоматически перераспределять ваши контролы соответствующим образом. Настоящее обновление описывается в реализации IRibbonForm:

Код:
public void RibbonHeightUpdated(int newHeight)
{
this.splitContainer1.SplitterDistance = newHeight;
}

Шаг 5 — Инициализировать Ribbon Framework при загрузке приложения
Чтобы инициализировать и уничтожить фреймворк ленты, обработайте события формы Load и FormClosed соответственно:

Код:
private void Form1_Load(object sender, EventArgs e)
{
_ribbon.InitFramework(this);
}

private void Form1_FormClosed(object sender, FormClosedEventArgs e)
{
_ribbon.DestroyFramework();
}

Наслаждайтесь своим первым WinForms-приложением с поддержкой Windows Ribbon!

Замечание: Если вы запускаете своё приложение и не видите ленту, попробуйте увеличить размер окна. Windows Ribbon обладает свойством не показываться, если размер окна слишком мал. К сожалению, стандартный размер окна в Visual Studio слишком мал.

Заключение
На этом пока всё. Теперь я хотел бы сделать несколько авторских замечаний.

1. Перевод сообщений Арика я осуществлял от первого лица. Делал я это для того, чтобы не загружать читателей лишними речевыми оборотами. Поэтому вам придётся самостоятельно различать, что в статьях написано от лица автора, а что — от лица Арика.

2. Нужно сказать, что эти сообщения Арик писал в процессе разработки своей библиотеки. Это значит, что в некоторых местах может проявляться будущее время и другие намёки на то, что разработка ещё идёт. На момент написания мной этой серии статей библиотека уже довольно долго находилась в стадии релиза, то есть все функции ленты она уже давно покрывает. Иными словами, всё написанное в статьях уже давно работает, вне зависимости от того, применено ли при описании будущее время или тому подобное.

3. В шаге, когда необходимо ссылаться на проект Ribbon.csproj, в оригинале было предложено ссылаться на саму библиотеку Ribbon.dll. Дело в том, что на данный момент Windows Ribbon for WinForms «поставляется» в виде не скомпилированного исходного кода, то есть библиотеку нужно также отдельно компилировать. Для упрощения можно просто добавить в решение проект библиотеки.

4. В третьем шаге у меня при компиляции возникли ошибки. Произошло это, возможно, потому, что в пути проекта были русские символы. Поэтому если у вас возникают ошибки при работе компиляторов UICC.exe или RC.exe, попробуйте убрать из пути проекта кириллицу.

Также в следующей статье будет некоторое замечание касаемо метода DestroyFramework. Сама же статья будет посвящена созданию меню приложения (Application Menu) с различными элементами управления.

Источник: thevista.ru

Оставить комментарий

Чтобы оставлять комментарии Вы должны быть авторизованы.

Похожие посты