Поделиться через


Кисти для композиции

Все видимое на экране в приложении WinUI отображается, так как оно было окрашено кистью. Кисти позволяют рисовать объекты пользовательского интерфейса с содержимым, начиная от простых сплошных цветов до изображений, рисунков и сложных цепочек эффектов. В этом разделе рассматриваются понятия живописи с помощью CompositionBrush.

При работе с приложением WinUI XAML вы можете окрасить UIElement с помощью кисти XAML или CompositionBrush. Как правило, проще выбрать кисть XAML, если сценарий уже поддерживается одним из них. Например, анимация цвета кнопки или изменение заливки текста или фигуры изображением. Если вам нужно что-то, что не поддерживается кистью XAML, например анимированная маска, анимированное девяти-ячейковое растяжение или цепочка эффектов, можно использовать CompositionBrush для рисования UIElement через XamlCompositionBrushBase.

При работе с визуальным слоем необходимо использовать CompositionBrush для рисования области SpriteVisual.

Необходимые условия

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

Рисование с помощью CompositionBrush

Объект CompositionBrush "красит" область со своими выходными данными. Разные кисти дают разные результаты. Некоторые инструменты для рисования закрашивают область сплошным цветом, другие используют градиент, изображение, пользовательский узор или эффект. Существуют также специализированные кисти, которые изменяют поведение других кистей. Например, маску непрозрачности можно использовать для управления областью, которую будет окрашивать CompositionBrush, а сетку из девяти частей можно использовать для управления растяжением, применяемым к CompositionBrush при рисовании области. CompositionBrush может быть одним из следующих типов:

Класс Сведения
CompositionColorBrush Закрашивает область сплошным цветом
CompositionSurfaceBrush Рисует область с содержимым ICompositionSurface
CompositionEffectBrush Закрашивает область, используя содержимое эффекта композиции.
CompositionMaskBrush Рисует изображение с помощью CompositionBrush с маской прозрачности
CompositionNineGridBrush Рисует область с помощью CompositionBrush, используя растяжение NineGrid
CompositionLinearGradientBrush Красит область с линейным градиентом
CompositionRadialGradientBrush Красит область с радиальным градиентом
CompositionBackdropBrush Рисует область путем выборки фоновых пикселей из приложения или пикселей непосредственно за окном приложения на рабочем столе. Используется в качестве входных данных для другого CompositionBrush, например CompositionEffectBrush

Краска с сплошным цветом

CompositionColorBrush закрашивает область однородным цветом. Существует множество способов указать цвет SolidColorBrush. Например, можно указать свои альфа-, красные, синие и зеленые каналы (ARGB) или использовать один из предопределенных цветов, предоставляемых классом Colors .

На следующем рисунке и в коде показано небольшое визуальное дерево для создания прямоугольника, обведенного черной кистью и закрашенного сплошной кистью с цветом 0x9ACD32.

CompositionColorBrush

Compositor _compositor;
ContainerVisual _container;
SpriteVisual _colorVisual1, _colorVisual2;
CompositionColorBrush _blackBrush, _greenBrush;

_compositor = ElementCompositionPreview.GetElementVisual(this).Compositor;
_container = _compositor.CreateContainerVisual();

_blackBrush = _compositor.CreateColorBrush(Colors.Black);
_colorVisual1 = _compositor.CreateSpriteVisual();
_colorVisual1.Brush = _blackBrush;
_colorVisual1.Size = new Vector2(156, 156);
_colorVisual1.Offset = new Vector3(0, 0, 0);
_container.Children.InsertAtBottom(_colorVisual1);

_greenBrush = _compositor.CreateColorBrush(Color.FromArgb(0xff, 0x9A, 0xCD, 0x32));
_colorVisual2 = _compositor.CreateSpriteVisual();
_colorVisual2.Brush = _greenBrush;
_colorVisual2.Size = new Vector2(150, 150);
_colorVisual2.Offset = new Vector3(3, 3, 0);
_container.Children.InsertAtBottom(_colorVisual2);

Краска с линейным градиентом

КомпозицияLinearGradientBrush рисует область с линейным градиентом. Линейный градиент объединяет два или более цветов по линии, градиентная ось. Объекты GradientStop используются для указания цветов в градиенте и их позициях.

На следующем рисунке и в коде показан SpriteVisual, нарисованный с помощью LinearGradientBrush с 2 остановками, используя красный и желтый цвета.

CompositionLinearGradientBrush

Compositor _compositor;
SpriteVisual _gradientVisual;
CompositionLinearGradientBrush _redyellowBrush;

_compositor = ElementCompositionPreview.GetElementVisual(this).Compositor;

_redyellowBrush = _compositor.CreateLinearGradientBrush();
_redyellowBrush.ColorStops.Add(_compositor.CreateColorGradientStop(0, Colors.Red));
_redyellowBrush.ColorStops.Add(_compositor.CreateColorGradientStop(1, Colors.Yellow));
_gradientVisual = _compositor.CreateSpriteVisual();
_gradientVisual.Brush = _redyellowBrush;
_gradientVisual.Size = new Vector2(156, 156);

Краска с радиальным градиентом

CompositionRadialGradientBrush рисует область с радиальным градиентом. Радиальный градиент сочетает два или более цветов с градиентом, начиная с центра эллипса и заканчивая радиусом эллипса. Объекты GradientStop используются для определения цветов и их расположения в градиенте.

На следующем рисунке и коде показан фрагмент SpriteVisual, нарисованный с помощью RadialGradientBrush с 2 GradientStops.

CompositionRadialGradientBrush

Compositor _compositor;
SpriteVisual _gradientVisual;
CompositionRadialGradientBrush RGBrush;

_compositor = ElementCompositionPreview.GetElementVisual(this).Compositor;

RGBrush = _compositor.CreateRadialGradientBrush();
RGBrush.ColorStops.Add(_compositor.CreateColorGradientStop(0, Colors.Aquamarine));
RGBrush.ColorStops.Add(_compositor.CreateColorGradientStop(1, Colors.DeepPink));
_gradientVisual = _compositor.CreateSpriteVisual();
_gradientVisual.Brush = RGBrush;
_gradientVisual.Size = new Vector2(200, 200);

Рисовать с помощью изображения

Объект CompositionSurfaceBrush заполняет область пикселями, отображаемыми на ICompositionSurface. Например, объект CompositionSurfaceBrush можно использовать для закрашивания области изображением, визуализированным на ICompositionSurface, используя API LoadedImageSurface.

На следующем рисунке и в коде показан SpriteVisual, окрашенный с растровым изображением лакрицы, отрендеренным на ICompositionSurface с помощью LoadedImageSurface. Свойства CompositionSurfaceBrush можно использовать для растяжения и выравнивания растрового изображения в пределах визуала.

CompositionSurfaceBrush

Compositor _compositor;
SpriteVisual _imageVisual;
CompositionSurfaceBrush _imageBrush;

_compositor = ElementCompositionPreview.GetElementVisual(this).Compositor;

_imageBrush = _compositor.CreateSurfaceBrush();

// The loadedSurface has a size of 0x0 till the image has been downloaded, decoded and loaded to the surface. We can assign the surface to the CompositionSurfaceBrush and it will show up once the image is loaded to the surface.
LoadedImageSurface _loadedSurface = LoadedImageSurface.StartLoadFromUri(new Uri("ms-appx:///Assets/licorice.jpg"));
_imageBrush.Surface = _loadedSurface;

_imageVisual = _compositor.CreateSpriteVisual();
_imageVisual.Brush = _imageBrush;
_imageVisual.Size = new Vector2(156, 156);

Рисование с помощью пользовательского рисунка

CompositionSurfaceBrush также может использоваться для закрашивания области пикселями из ICompositionSurface, отрисованного с помощью Win2D (или D2D).

В следующем коде показан SpriteVisual, на котором отображается текст, отрисованный на ICompositionSurface с помощью Win2D. Чтобы использовать Win2D с WinUI, установите пакет NuGet Microsoft.Graphics.Win2D в проекте.

Compositor _compositor;
CanvasDevice _device;
CompositionGraphicsDevice _compositionGraphicsDevice;
SpriteVisual _drawingVisual;
CompositionSurfaceBrush _drawingBrush;

_compositor = ElementCompositionPreview.GetElementVisual(this).Compositor;
_device = CanvasDevice.GetSharedDevice();
_compositionGraphicsDevice = CanvasComposition.CreateCompositionGraphicsDevice(_compositor, _device);

_drawingBrush = _compositor.CreateSurfaceBrush();
CompositionDrawingSurface _drawingSurface = _compositionGraphicsDevice.CreateDrawingSurface(
    new Size(256, 256),
    DirectXPixelFormat.B8G8R8A8UIntNormalized,
    DirectXAlphaMode.Premultiplied);

using (var ds = CanvasComposition.CreateDrawingSession(_drawingSurface))
{
    ds.Clear(Colors.Transparent);
    var rect = new Rect(new Point(2, 2), (_drawingSurface.Size.ToVector2() - new Vector2(4, 4)).ToSize());
    ds.FillRoundedRectangle(rect, 15, 15, Colors.LightBlue);
    ds.DrawRoundedRectangle(rect, 15, 15, Colors.Gray, 2);
    ds.DrawText("This is a composition drawing surface", rect, Colors.Black, new CanvasTextFormat()
    {
        FontFamily = "Comic Sans MS",
        FontSize = 32,
        WordWrapping = CanvasWordWrapping.WholeWord,
        VerticalAlignment = CanvasVerticalAlignment.Center,
        HorizontalAlignment = CanvasHorizontalAlignment.Center
    });
}

_drawingBrush.Surface = _drawingSurface;

_drawingVisual = _compositor.CreateSpriteVisual();
_drawingVisual.Brush = _drawingBrush;
_drawingVisual.Size = new Vector2(156, 156);

Аналогично, CompositionSurfaceBrush также можно использовать для рисования объекта SpriteVisual с помощью SwapChain и взаимодействия с Win2D. Этот образец предоставляет пример использования Win2D для рисования SpriteVisual с использованием swapchain.

Рисование с помощью видео

CompositionSurfaceBrush также можно использовать для закрашивания области пикселями с поверхности ICompositionSurface, рендеренной с помощью видео, загруженного через класс MediaPlayer.

В следующем коде показано SpriteVisual с загруженным на ICompositionSurface видео.

Compositor _compositor;
SpriteVisual _videoVisual;
CompositionSurfaceBrush _videoBrush;

_compositor = ElementCompositionPreview.GetElementVisual(this).Compositor;

// MediaPlayer setup with a source URI.
_mediaPlayer = new MediaPlayer();

// Get a source from a URI. This could also come from a file or a stream.
var source = MediaSource.CreateFromUri(new Uri("https://go.microsoft.com/fwlink/?LinkID=809007&clcid=0x409"));
var item = new MediaPlaybackItem(source);
_mediaPlayer.Source = item;
_mediaPlayer.IsLoopingEnabled = true;

// Get the surface from MediaPlayer and put it on a brush.
_videoSurface = _mediaPlayer.GetSurface(_compositor);
_videoBrush = _compositor.CreateSurfaceBrush(_videoSurface.CompositionSurface);

_videoVisual = _compositor.CreateSpriteVisual();
_videoVisual.Brush = _videoBrush;
_videoVisual.Size = new Vector2(156, 156);

Краска с эффектом фильтра

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

На следующем изображении и в коде показан SpriteVisual с изображением кота, к которому применен эффект фильтра десатурации.

CompositionEffectBrush

Compositor _compositor;
SpriteVisual _effectVisual;
CompositionEffectBrush _effectBrush;

_compositor = ElementCompositionPreview.GetElementVisual(this).Compositor;

var graphicsEffect = new SaturationEffect
{
    Saturation = 0.0f,
    Source = new CompositionEffectSourceParameter("mySource")
};

var effectFactory = _compositor.CreateEffectFactory(graphicsEffect);
_effectBrush = effectFactory.CreateBrush();

CompositionSurfaceBrush surfaceBrush = _compositor.CreateSurfaceBrush();
LoadedImageSurface loadedSurface = LoadedImageSurface.StartLoadFromUri(new Uri("ms-appx:///Assets/cat.jpg"));
surfaceBrush.Surface = loadedSurface;

_effectBrush.SetSourceParameter("mySource", surfaceBrush);

_effectVisual = _compositor.CreateSpriteVisual();
_effectVisual.Brush = _effectBrush;
_effectVisual.Size = new Vector2(156, 156);

Дополнительные сведения о создании эффекта с помощью CompositionBrushes см. в разделе "Эффекты" в визуальном слое

Красьте при помощи CompositionBrush с примененной маской непрозрачности

CompositionMaskBrush рисует область с CompositionBrush с маской непрозрачности, применённой к нему. Источником маски непрозрачности может быть любой CompositionBrush типа CompositionColorBrush, CompositionLinearGradientBrush, CompositionSurfaceBrush, CompositionEffectBrush или CompositionNineGridBrush. Маска непрозрачности должна быть указана как CompositionSurfaceBrush.

На следующем рисунке и в коде показан SpriteVisual, окрашенный с использованием CompositionMaskBrush. Источником маски является CompositionLinearGradientBrush, который маскируется, чтобы выглядеть как круг, используя изображение круга в качестве маски.

CompositionMaskBrush

Compositor _compositor;
SpriteVisual _maskVisual;
CompositionMaskBrush _maskBrush;

_compositor = ElementCompositionPreview.GetElementVisual(this).Compositor;

_maskBrush = _compositor.CreateMaskBrush();

CompositionLinearGradientBrush _sourceGradient = _compositor.CreateLinearGradientBrush();
_sourceGradient.ColorStops.Add(_compositor.CreateColorGradientStop(0,Colors.Red));
_sourceGradient.ColorStops.Add(_compositor.CreateColorGradientStop(1,Colors.Yellow));
_maskBrush.Source = _sourceGradient;

LoadedImageSurface loadedSurface = LoadedImageSurface.StartLoadFromUri(new Uri("ms-appx:///Assets/circle.png"), new Size(156.0, 156.0));
_maskBrush.Mask = _compositor.CreateSurfaceBrush(loadedSurface);

_maskVisual = _compositor.CreateSpriteVisual();
_maskVisual.Brush = _maskBrush;
_maskVisual.Size = new Vector2(156, 156);

Краска с помощью CompositionBrush с помощью stretch NineGrid

CompositionNineGridBrush рисует область при помощи CompositionBrush. Эта кисть растягивается с использованием метафоры девяти-сеток. Метафора с девятью ячейками позволяет растягивать края и уголки CompositionBrush иначе, чем его центр. Источник девятисетевого растяжения может быть любой CompositionBrush типа CompositionColorBrush, CompositionSurfaceBrush или CompositionEffectBrush.

В следующем коде показан SpriteVisual, окрашенный с использованием CompositionNineGridBrush. Источник маски - это CompositionSurfaceBrush, растянутый с помощью сетки 3x3.

Compositor _compositor;
SpriteVisual _nineGridVisual;
CompositionNineGridBrush _nineGridBrush;

_compositor = ElementCompositionPreview.GetElementVisual(this).Compositor;

_nineGridBrush = _compositor.CreateNineGridBrush();

// nineGridImage.png is 50x50 pixels; nine-grid insets, as measured relative to the actual size of the image, are: left = 1, top = 5, right = 10, bottom = 20 (in pixels)
LoadedImageSurface _imageSurface = LoadedImageSurface.StartLoadFromUri(new Uri("ms-appx:///Assets/nineGridImage.png"));
CompositionSurfaceBrush sourceBrush = _compositor.CreateSurfaceBrush(_imageSurface);
_nineGridBrush.Source = sourceBrush;

// Set nine-grid insets.
_nineGridBrush.SetInsets(1, 5, 10, 20);

// Set the appropriate stretch on the SurfaceBrush for the center of the nine-grid.
sourceBrush.Stretch = CompositionStretch.Fill;

_nineGridVisual = _compositor.CreateSpriteVisual();
_nineGridVisual.Brush = _nineGridBrush;
_nineGridVisual.Size = new Vector2(100, 75);

Рисуйте, используя фоновые пиксели

CompositionBackdropBrush закрашивает область содержимым, находящимся за этой областью. CompositionBackdropBrush никогда не используется самостоятельно, но вместо этого используется в качестве входных данных для другого CompositionBrush, как EffectBrush. Например, используя CompositionBackdropBrush в качестве входа для эффекта размытия, можно достичь эффекта матового стекла.

В следующем коде показано небольшое визуальное дерево для создания изображения с использованием CompositionSurfaceBrush и эффектом матового стекла поверх изображения. Наложение матированного стекла создается путем размещения SpriteVisual, заполненного эффектом Brush, над изображением. EffectBrush использует CompositionBackdropBrush в качестве входных данных для эффекта размытия.

Compositor _compositor;
ContainerVisual _containerVisual;
SpriteVisual _imageVisual;
SpriteVisual _backdropVisual;

_compositor = ElementCompositionPreview.GetElementVisual(this).Compositor;

// Create a container visual to host the visual tree.
_containerVisual = _compositor.CreateContainerVisual();

// Create _imageVisual and add it to the bottom of the container visual.
CompositionSurfaceBrush _licoriceBrush = _compositor.CreateSurfaceBrush();
LoadedImageSurface loadedSurface = LoadedImageSurface.StartLoadFromUri(new Uri("ms-appx:///Assets/licorice.jpg"));
_licoriceBrush.Surface = loadedSurface;

_imageVisual = _compositor.CreateSpriteVisual();
_imageVisual.Brush = _licoriceBrush;
_imageVisual.Size = new Vector2(156, 156);
_imageVisual.Offset = new Vector3(0, 0, 0);
_containerVisual.Children.InsertAtBottom(_imageVisual);

// Create a SpriteVisual and add it to the top of the container visual.
// Paint the visual with an EffectBrush that applies blur to the content underneath it.
GaussianBlurEffect blurEffect = new GaussianBlurEffect()
{
    Name = "Blur",
    BlurAmount = 1.0f,
    BorderMode = EffectBorderMode.Hard,
    Source = new CompositionEffectSourceParameter("source")
};

CompositionEffectFactory blurEffectFactory = _compositor.CreateEffectFactory(blurEffect);
CompositionEffectBrush _backdropBrush = blurEffectFactory.CreateBrush();

// Create a BackdropBrush and bind it to the EffectSourceParameter source.
_backdropBrush.SetSourceParameter("source", _compositor.CreateBackdropBrush());

_backdropVisual = _compositor.CreateSpriteVisual();
_backdropVisual.Brush = _backdropBrush;
_backdropVisual.Size = new Vector2(78, 78);
_backdropVisual.Offset = new Vector3(39, 39, 0);
_containerVisual.Children.InsertAtTop(_backdropVisual);

Объединение compositionBrushes

Ряд композиционных кистей использует другие композиционные кисти в качестве вводных данных. Например, с помощью метода SetSourceParameter можно задать другой CompositionBrush в качестве входных данных в CompositionEffectBrush. В таблице ниже приведены поддерживаемые сочетания CompositionBrushes. Обратите внимание, что использование неподдерживаемой комбинации приведет к возникновению исключения.

Щетка EffectBrush.SetSourceParameter() MaskBrush.Mask MaskBrush.Source NineGridBrush.Source
CompositionColorBrush ДА ДА ДА ДА
CompositionLinear
Градиентная Кисть
ДА ДА ДА НЕТ
CompositionSurfaceBrush ДА ДА ДА ДА
CompositionEffectBrush НЕТ НЕТ ДА НЕТ
Класс CompositionMaskBrush (Кисть с маской компоновки) НЕТ НЕТ НЕТ НЕТ
CompositionNineGridBrush ДА ДА ДА НЕТ
CompositionBackdropBrush ДА НЕТ НЕТ НЕТ

Использование кисти XAML по сравнению с CompositionBrush

В следующей таблице приводится список сценариев и указания, когда следует использовать кисть XAML или Composition при рисовании UIElement или SpriteVisual в вашем приложении.

Замечание

Если для XAML UIElement предлагается CompositionBrush, предполагается, что CompositionBrush упакован с помощью XamlCompositionBrushBase.

Сценарий XAML UIElement Композиция SpriteVisual
Закрасьте область сплошным цветом Solidcolorbrush CompositionColorBrush
Рисование области с анимированным цветом Solidcolorbrush CompositionColorBrush
Закрасьте область с использованием статического градиента. LinearGradientBrush CompositionLinearGradientBrush
Покраска области с анимированными точками градиента CompositionLinearGradientBrush CompositionLinearGradientBrush
Рисование области изображением ImageBrush CompositionSurfaceBrush
Рисование области с помощью веб-страницы WebView2 N/A
Рисование области с изображением с помощью stretch NineGrid Элемент управления изображением CompositionNineGridBrush
Рисование области с анимацией растягивания по схеме NineGrid CompositionNineGridBrush CompositionNineGridBrush
Окрасить область с помощью цепочки обмена кадрами SwapChainPanel CompositionSurfaceBrush с swapchain interop
Рисование области с помощью видео MediaPlayerElement CompositionSurfaceBrush с взаимодействием с мультимедиа
Закрасить область при помощи пользовательского 2D-рисунка CanvasControl из Win2D CompositionSurfaceBrush с поддержкой Win2D interop
Закрасить область неанимированной маской Определение маски с помощью фигур XAML CompositionMaskBrush
Рисование области с анимированной маской CompositionMaskBrush CompositionMaskBrush
Рисование области с эффектом анимированного фильтра CompositionEffectBrush CompositionEffectBrush
Закрасьте область с применением эффекта к фоновым пикселям CompositionBackdropBrush CompositionBackdropBrush

Создание собственного взаимодействия DirectX и Direct2D с BeginDraw и EndDraw

Взаимодействие кисти XAML с XamlCompositionBrushBase