Partilhar via


Pincéis de composição

Tudo o que está visível no ecrã numa aplicação do WinUI é visível porque foi pintado com um pincel. Os pincéis permitem-lhe pintar objetos da interface de utilizador (UI) com conteúdos que vão desde cores sólidas simples até imagens, desenhos e cadeias de efeitos complexas. Este tópico introduz os conceitos de pintura com CompositionBrush.

Ao trabalhar com uma aplicação WinUI XAML, pode escolher pintar um UIElement com um pincel XAML ou um CompositionBrush. Normalmente, é mais fácil escolher um pincel XAML se o teu cenário já for suportado por um. Por exemplo, animar a cor de um botão ou alterar o preenchimento de texto ou de uma forma com uma imagem. Se precisar de algo que não seja suportado por um pincel XAML, como uma máscara animada, um estiramento animado de nove grelhas ou uma cadeia de efeitos, pode usar um CompositionBrush para pintar um UIElement através do XamlCompositionBrushBase.

Ao trabalhar com a camada Visual, é necessário usar um CompositionBrush para pintar a área de um SpriteVisual.

Pré-requisitos

Esta visão geral assume que está familiarizado com a estrutura de uma aplicação básica de Composição, conforme descrito na visão geral da camada Visual.

Pintar com um Pincel de Composição

Um CompositionBrush "pinta" uma área com a sua saída. Diferentes escovas têm diferentes tipos de saída. Alguns pincéis pintam uma área com uma cor sólida, outros com um gradiente, imagem, desenho personalizado ou efeito. Existem também pincéis especializados que modificam o comportamento de outros pincéis. Por exemplo, uma máscara de opacidade pode controlar qual área é pintada por um CompositionBrush, ou uma grelha de nove partes pode controlar o estiramento aplicado a um CompositionBrush ao pintar uma área. CompositionBrush pode ser de um dos seguintes tipos:

Classe Detalhes
CompositionColorBrush Pinta uma área com uma cor sólida
CompositionSurfaceBrush Pinta uma área com o conteúdo de um ICompositionSurface
CompositionEffectBrush Pinta uma área com o conteúdo de um efeito de composição
CompositionMaskBrush Pinta um elemento visual com um CompositionBrush utilizando uma máscara de opacidade
ComposiçãoPincelNoveQuadrados Pinta uma área com um CompositionBrush usando um NineGrid stretch
ComposiçãoGradienteLinear Brush Pinta uma área com um gradiente linear
CompositionRadialGradientBrush Pinta uma área com um gradiente radial
CompositionBackdropBrush Pinta uma área amostrando pixels de fundo da aplicação ou diretamente atrás da janela da aplicação no ambiente de trabalho. Usado como entrada para outro CompositionBrush, como um CompositionEffectBrush

Pinta com uma cor sólida

A CompositionColorBrush pinta uma área com uma cor sólida. Existem várias formas de especificar a cor de um SolidColorBrush. Por exemplo, pode especificar os seus canais alfa, vermelho, azul e verde (ARGB) ou usar uma das cores pré-definidas fornecidas pela classe Cores .

A ilustração e o código seguintes mostram uma pequena árvore visual para criar um retângulo que é traçado com um pincel de cor preta e pintado com um pincel de cor sólida que tem o valor de cor de 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);

Pintar com um gradiente linear

Um CompositionLinearGradientBrush pinta uma área com um gradiente linear. Um gradiente linear mistura duas ou mais cores ao longo de uma linha, o eixo do gradiente. Usas objetos GradientStop para especificar as cores no gradiente e as suas posições.

A ilustração e o código seguintes mostram um SpriteVisual pintado com um LinearGradientBrush com 2 stops, usando as cores vermelha e amarela.

ComposiçãoGradienteLinear Brush

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);

Pintura com gradiente radial

CompositionRadialGradientBrush pinta uma área com um gradiente radial. Um gradiente radial mistura duas ou mais cores, com o gradiente começando no centro da elipse e terminando no raio da elipse. Os objetos GradientStop são usados para definir as cores e a sua localização no gradiente.

A ilustração e o código seguintes mostram um SpriteVisual pintado com um RadialGradientBrush com 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);

Pintar com uma imagem

CompositionSurfaceBrush pinta uma área com píxeis que são renderizados numa ICompositionSurface. Por exemplo, um CompositionSurfaceBrush pode ser usado para pintar uma área com uma imagem renderizada numa ICompositionSurface usando a API LoadedImageSurface .

A ilustração e o código seguintes mostram um SpriteVisual pintado com um bitmap de um alcaçuz renderizado numa ICompositionSurface usando LoadedImageSurface. As propriedades do CompositionSurfaceBrush podem ser usadas para esticar e alinhar o bitmap dentro dos limites do visual.

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);

Pinte com um desenho personalizado

Um CompositionSurfaceBrush também pode ser usado para pintar uma área com pixels de um ICompositionSurface renderizado usando Win2D (ou D2D).

O código seguinte mostra um SpriteVisual pintado com uma sequência de texto renderizada numa ICompositionSurface usando Win2D. Para usar Win2D com WinUI, instale o pacote NuGet Microsoft.Graphics.Win2D no seu projeto.

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);

De forma semelhante, o CompositionSurfaceBrush também pode ser utilizado para renderizar um SpriteVisual com uma cadeia de troca utilizando interoperabilidade Win2D. Este exemplo fornece um exemplo de como usar o Win2D para pintar um SpriteVisual com uma swapchain.

Pintar com um vídeo

Um CompositionSurfaceBrush também pode ser utilizado para pintar uma área com píxeis provenientes de um ICompositionSurface renderizado através de um vídeo carregado pela classe MediaPlayer.

O código seguinte mostra um SpriteVisual pintado com um vídeo carregado num 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);

Pintar com efeito de filtro

Um CompositionEffectBrush pinta uma área com a saída do CompositionEffect. Os efeitos na Camada Visual podem ser vistos como efeitos de filtro animáveis aplicados a uma coleção de conteúdos de fonte, como cores, gradientes, imagens, vídeos, swapchains, regiões da sua interface ou árvores de elementos visuais. O conteúdo de origem é normalmente especificado usando outro CompositionBrush.

A ilustração e o código a seguir mostram um SpriteVisual pintado com uma imagem de um gato, onde foi aplicado um efeito de filtro de desaturação.

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);

Para mais informações sobre como criar um Efeito usando CompositionBrushes, veja Efeitos na camada Visual

Pintar com um CompositionBrush com máscara de opacidade aplicada

Um CompositionMaskBrush pinta uma área com um CompositionBrush que possui uma máscara de opacidade aplicada. A fonte da máscara de opacidade pode ser qualquer Pincel de Composição do tipo PincelCor de Composição, PincelGradienteLinear de Composição, PincelSuperfície de Composição, PincelEfeito de Composição ou PincelNoveGrelha de Composição. A máscara de opacidade deve ser especificada como um CompositionSurfaceBrush.

A ilustração e o código seguintes mostram um SpriteVisual pintado com um CompositionMaskBrush. A fonte da máscara é um CompositionLinearGradientBrush, que é mascarado para parecer um círculo utilizando uma imagem de círculo como máscara.

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);

Pinte com um Pincel de ComposiçãoUsando o NineGrid stretch

A CompositionNineGridBrush pinta uma área com um CompositionBrush que é esticada usando a metáfora das nove grelhas. A metáfora das nove grelhas permite-lhe esticar as bordas e cantos de um CompositionBrush de forma diferente do seu centro. A fonte do esticar de nove grelhas pode ser qualquer CompositionBrush do tipo CompositionColorBrush, CompositionSurfaceBrush ou CompositionEffectBrush.

O código seguinte mostra um SpriteVisual pintado com um CompositionNineGridBrush. A fonte da máscara é um CompositionSurfaceBrush que é expandido através de uma grade de nove partes.

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);

Pintar usando Píxeis de Fundo

Um pincel de fundo de composição pinta uma área com o conteúdo por trás da área. Um CompositionBackdropBrush nunca é usado isoladamente, mas sim usado como entrada para outro CompositionBrush, como um EffectBrush. Por exemplo, ao usar um CompositionBackdropBrush como entrada para um efeito de Desfoque, pode obter um efeito de vidro fosco.

O código seguinte mostra uma pequena árvore visual para criar uma imagem usando CompositionSurfaceBrush e uma sobreposição de vidro fosco acima da imagem. A sobreposição de vidro fosco é criada colocando um SpriteVisual preenchido com um EffectBrush acima da imagem. O EffectBrush usa um CompositionBackdropBrush como entrada para o efeito de desfoque.

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);

Combinação de Composição Pincéis

Vários CompositionBrushes utilizam outros CompositionBrushes como entradas. Por exemplo, o método SetSourceParameter pode ser usado para definir outro CompositionBrush como entrada para um CompositionEffectBrush. A tabela abaixo descreve as combinações suportadas de CompositionBrushes. Note que usar uma combinação não suportada lançará uma exceção.

Escova EffectBrush.SetSourceParameter() MaskBrush.Mask MaskBrush.Source NineGridBrush.Source
ComposiçãoPincel de Cor SIM SIM SIM SIM
ComposiçãoLinear
GradientBrush
SIM SIM SIM Não
CompositionSurfaceBrush SIM SIM SIM SIM
Pincel de Efeito de Composição Não Não SIM Não
ComposiçãoMáscaraPincel Não Não Não Não
ComposiçãoNovePincel da Grelha SIM SIM SIM Não
OrnamentaçãoBackdropBrush SIM Não Não Não

Usar um Pincel XAML vs. Pincel de Composição

A tabela abaixo apresenta uma lista de cenários e se o uso de pincel XAML ou pincel de Composição é prescrito para pintar um UIElement ou um SpriteVisual na sua aplicação.

Observação

Se for sugerido um CompositionBrush para um UIElement XAML, assume-se que o CompositionBrush está embalado utilizando uma XamlCompositionBrushBase.

Scenario XAML UIElement Composição SpriteVisual
Pinte uma área com cor sólida SolidColorBrush ComposiçãoPincel de Cor
Pinta uma área com cor animada SolidColorBrush CompositionColorBrush
Pinte uma área com um gradiente estático LinearGradientBrush ComposiçãoGradienteLinear Brush
Pinta uma área com paradas de gradiente animadas ComposiçãoGradienteLinear Brush ComposiçãoGradienteLinear Brush
Pinte uma área com uma imagem ImageBrush CompositionSurfaceBrush
Pinte uma área com uma página web WebView2 N/A
Pinte uma área com uma imagem usando o NineGrid stretch Controlo de Imagem Composição da Grade de Nove Pincéis
Pinta uma área com alongamento animado do NineGrid Pincel-de-Composição-nove-da-grelha ComposiçãoPincelNoveQuadrados
Pinte uma área com um swapchain SwapChainPanel CompositionSurfaceBrush com interoperabilidade de swapchain
Pinta uma área com um vídeo MediaPlayerElement CompositionSurfaceBrush com interoperação de média
Pinte uma área com desenhos 2D personalizados CanvasControl do Win2D CompositionSurfaceBrush com interoperabilidade com Win2D
Pinta uma área com máscara não animada Utilize formas XAML para definir uma máscara CompositionMaskBrush
Pinta uma área com uma máscara animada CompositionMaskBrush CompositionMaskBrush
Pinte uma área com um efeito de filtro animado CompositionEffectBrush CompositionEffectBrush
Pinte uma área com um efeito aplicado aos píxeis do fundo CompositionBackdropBrush CompositionBackdropBrush

Interoperação nativa DirectX e Direct2D com BeginDraw e EndDraw

Interoperabilidade de pincéis XAML com XamlCompositionBrushBase