Эта статья продолжает серию наших рассказов, в которых мы делимся своим опытом разработки визуальных WinRT контролов в стиле Windows 8 UI.
Впрошлый размы приводили базовые шаги, необходимые для создания своего WinRT контрола и SDK для него, а сейчас речь пойдёт о применении технологии Direct2D для создания визуальных эффектов в вашем WinRT компоненте.
В данной статье мы рассмотрим процесс создания кругового индикатора aka гейдж (gauge control), у которого стрелка будет размываться при движении.
ТехнологияDirect2D- это ускоренный аппаратным обеспечением API для двухмерной графики, который обеспечивает высокую производительность и высококачественное отображение двухмерной геометрии, растровых изображений и текста.
Direct2D API разработан компанией Microsoft для создания приложений под управлением операционной системы Windows и для взаимодействия с существующим кодом, который использует GDI, GDI+, или Direct3D.
Когда бывает необходимо использовать Direct2D в своих приложениях?
Типичным примером является оптимизация производительности приложений, в которых происходит отрисовка большого количества графических элементов (например, такое бывает нужно при создании графиков с большим объёмом данных, карт и всевозможных индикаторов-гейджей).
Более подробно узнать про Direct2D и особенности её применения можно всоответствующем разделеMSDN.
Системные требования
Для разработки приложений в стиле Windows 8 UI (METRO) вам понадобятся Windows 8 и Visual Studio 2012. Более подробно об этом можно прочитать в нашейпредыдущей статье.
Создание С++ библиотеки с компонентом, использующим Direct2D
Чтобы использовать Direct2D в вашем приложении, надо написать WinRT компонент на C++.
Для этого выполним следующие шаги:
Запустим Visual Studio 2012 (если вы её вообще когда-либо закрываете :-) )
Создадим новый Visual C++ проект типа Windows Runtime Component
Данная библиотека будет содержать реализацию объявление и реализацию нескольких интерфейсов, предназначенных для отрисовки с помощью технологии Direct2D.
Затем необходимо в свойствах нашего C++ проекта добавить ссылки на библиотеки Direct2D: d2d1.lib и d3d11.lib.
Далее необходимо написать реализацию отрисовки нашего компонента с использованием Direct2D.
Во-первых, создаем статический классDrawingFactoryс одним единственным методомCreateRenderer, который будет инициализировать библиотеку DirectX, создавать и возвращать экземпляр классаRenderer:
public ref classDrawingFactorysealed {public:
static IRenderer^ CreateRenderer();
};
Во-вторых, описываем основной интерфейсIRenderer, который будет содержать следующие методы и свойства: - методReset, предназначенный для пересоздания поверхности для рисования, в нашем случае этоImageBrushс размерами, которые были переданы. В дальнейшем полученнуюImageBrushмы будем присваивать какому-либо элементу в визуальном дереве нашего WinRT компонента; - свойствоTargetBrush, которое будет возвращать созданную кисть в методеResetи должен содержать результат отрисовки; - свойстваEnableMotionBlur,MotionBlurAngle,MotionBlurDeviation, которые служат для включения и настройки эффекта размытия при рендеринге примитивов; - методыCreateGeometry,DrawGeometry,FillGeometry, предназначенные для создания и рисования геометрий; - Кроме того рассматриваемый интерфейс содержит еще несколько простых и понятных методов и свойств, таких какBeginDraw,EndDraw,Clear,TargetWidthиTargetHeight.
А теперь расскажем о том, как мы будем делать эффект размытия. С Direct2D данная задача решается очень просто. В методе Reset нужно создать стандартныйDirectionalBlureffect, и временный битмап (m_inputSource), в который будем рисовать и использовать его в качестве источника для ранее созданного эффекта:
Затем в методеBeginDrawв качестве поверхности для рисования, используем промежуточный битмапm_inputSource, а при завершении рисования в методеEndDrawустанавливаем поверхностьTargetBrushи, в зависимости от значения свойстваEnableMotionBlur, рисуем либо эффект, либо промежуточный битмап.
Создание С# библиотеки, содержащей WinRT компонент
На следующем этапе необходимо добавить в наше решение ещё один проект - на этот раз C#. Этот проект представляет собой библиотеку, содержащую WinRT компонент, который будет оперировать с написанной ранее C++ библиотекой.
Для этого проекта нужно добавить ссылки на созданную ранее C++ сборку:
В этой библиотеке будет содержаться собственно сам WinRT Gauge. Чтобы включить его в нашу сборку, добавим новый Templated Control:
Все визуальные элементы, кроме стрелки, будем отрисовывать стандартными средствами WinRT, а именно, зададим в темплейте:
В рассматриваемом визуальном представлении компонента есть пустойBorderс именемRendererSurface. Данный элемент получим в методеOnApplyTemplateи сохраним в переменную класса, чтобы затем в его свойствоBackgroundприсвоитьBrushизrenderer.
В конструкторе нашего класса мы должны c помощьюDrawingFactoryсоздатьIRenderer, а также подписаться на событиеSizeChanged. На этом событии будем вызывать методIRenderer.Reset, для того чтобы размер кисти, в которую будет производится отрисовка, соответствовал размеру компонента. Также подписываемся на статическое событиеCompositionTarget.Rendering- на обработчике этого события мы будем рисовать нашу стрелку.
Теперь нам остается только добавить одно свойство зависимостиValueи отрисовать геометрию стрелки:
static readonly DependencyProperty ValueProperty = DependencyProperty.Register("Value",
typeof(double), typeof(Gauge), new PropertyMetadata(0.0, ValuePropertyChanged));
public double Value {
get { return (double)GetValue(ValueProperty); }set { SetValue(ValueProperty, value); }
}
public static void ValuePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) {
Gauge gauge = d as Gauge;
if (gauge != null)
gauge.renderer.EnableMotionBlur = true;
}
void Render() {
double angle = Math.PI * Value / 1000 - Math.PI / 2.0;
IShapeGeometry geometry = CreateArrowGeometry(angle);
renderer.BeginDraw();
renderer.MotionBlurAngle = (float)(angle / Math.PI * 180);
renderer.MotionBlurDeviation = 5.0f;
renderer.Clear(Colors.Transparent);
renderer.FillGeometry(arrow, ColorHelper.FromArgb(0xFF, 0xD3, 0x65, 0xF8));
renderer.DrawGeometry(arrow, ColorHelper.FromArgb(0xFF, 0xD3, 0xAA, 0xF8), 3.0f);
renderer.EndDraw();
if (renderer.EnableMotionBlur)
renderer.EnableMotionBlur = false;
}
Вот и всё. Наш компонент готов, и теперь мы можем использовать его в реальном приложении.
Использование WinRT компонента Gauge
Для того, чтобы продемонстрировать работу нашего компонента, добавим ещё один проект в наше решение. Пусть это будет шаблонBlank App (XAML). Назовём наш тестовый проектGaugeMatrix:
Затем в этот проект добавим ссылки на проекты Gauge и DrawingLayer, созданные ранее:
Далее добавимGridвMainPage.xamlи создадим в нём две строки и два столбца.
После этого в каждую ячейку кладем наш компонентGauge, а такжеSliderдлядинамического изменения значения, отображаемого с помощью стрелки наGaugeконтроле:
Делаем проектGaugeMatrixстартовым, запускаем приложение и… всё, у вас получилось использовать рисование с помощью Direct2D в вашем WinRT приложении! Поздравляем!