Compartir a través de


Pinceles de composición

Todo lo que está visible en la pantalla en una aplicación WinUI es visible porque fue pintado por un pincel. Los pinceles permiten pintar objetos de interfaz de usuario (UI) con contenido que va desde colores sólidos simples hasta imágenes, dibujos y cadenas de efectos complejas. En este tema se presentan los conceptos de pintura con CompositionBrush.

Al trabajar con una aplicación XAML de WinUI, puedes elegir pintar un UIElement con un pincel XAML o compositionBrush. Normalmente, es más fácil elegir un pincel XAML si el escenario ya es compatible con uno. Por ejemplo, animar el color de un botón o cambiar el relleno de texto o una forma con una imagen. Si necesitas algo que no sea compatible con un pincel XAML, como una máscara animada, una extensión animada de nueve cuadrículas o una cadena de efectos, puedes usar compositionBrush para pintar un UIElement a través de XamlCompositionBrushBase.

Al trabajar con la capa visual, se debe usar compositionBrush para pintar el área de un SpriteVisual.

Prerrequisitos

En esta visión general se da por supuesto que está familiarizado con la estructura de una aplicación de composición básica, como se describe en la información general de la capa Visual.

Pintar con un pincel de composición

Un CompositionBrush "pinta" un área con su salida. Los pinceles diferentes tienen diferentes tipos de salida. Algunos pinceles pintan un área con un color sólido, otros con un degradado, una imagen, un dibujo personalizado o un efecto. También hay pinceles especializados que modifican el comportamiento de otros pinceles. Por ejemplo, la máscara de opacidad se puede usar para controlar qué área está pintada por un CompositionBrush, o se puede usar una cuadrícula de nueve para controlar la extensión aplicada a un CompositionBrush al pintar un área. CompositionBrush puede ser de uno de los siguientes tipos:

Class Detalles
CompositionColorBrush Pinta un área con un color sólido
CompositionSurfaceBrush Dibuja un área utilizando el contenido de un ICompositionSurface
CompositionEffectBrush Pinta un área con el contenido de un efecto de composición
CompositionMaskBrush Pinta un objeto visual con un CompositionBrush y una máscara de opacidad
CompositionNineGridBrush Pinta un área con un CompositionBrush usando un estiramiento de NineGrid
CompositionLinearGradientBrush Pinta un área con un degradado lineal
CompositionRadialGradientBrush Pinta un área con un degradado radial
CompositionBackdropBrush Pinta un área mediante el muestreo de píxeles de fondo de la aplicación o píxeles directamente detrás de la ventana de la aplicación en el escritorio. Se usa como entrada para otro CompositionBrush como el CompositionEffectBrush

Pintar con un color sólido

Un CompositionColorBrush pinta un área con un color sólido. Hay una variedad de maneras de especificar el color de un SolidColorBrush. Por ejemplo, puede especificar sus canales alfa, rojo, azul y verde (ARGB) o usar uno de los colores predefinidos proporcionados por la clase Colors .

En la siguiente ilustración y código se muestra un pequeño árbol visual para crear un rectángulo que se trazó con un pincel de color negro y se pinta con un pincel de color sólido que tiene el valor de color 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 con un degradado lineal

CompositionLinearGradientBrush pinta un área con un degradado lineal. Un degradado lineal combina dos o más colores a través de una línea, el eje de degradado. Los objetos GradientStop se usan para especificar los colores en el degradado y sus posiciones.

En la siguiente ilustración y código se muestra un SpriteVisual pintado con LinearGradientBrush con 2 puntos utilizando colores rojo y amarillo.

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

Pintar con un degradado radial

Un CompositionRadialGradientBrush pinta un área con un degradado radial. Un degradado radial combina dos o más colores con el degradado comenzando desde el centro de la elipse y finalizando en el radio de la elipse. Los objetos GradientStop se usan para definir los colores y su ubicación en el degradado.

En la siguiente ilustración y código se muestra un SpriteVisual pintado con un RadialGradientBrush con 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 con una imagen

Un CompositionSurfaceBrush pinta un área con píxeles representados en un ICompositionSurface. Por ejemplo, se puede usar CompositionSurfaceBrush para pintar un área con una imagen que se ha renderizado en un ICompositionSurface mediante la API LoadedImageSurface.

En la siguiente ilustración y código se muestra un SpriteVisual pintado con un bitmap de un regaliz representado en un ICompositionSurface mediante LoadedImageSurface. Las propiedades de CompositionSurfaceBrush se pueden usar para estirar y alinear el mapa de bits dentro de los límites del 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);

Pintar con un dibujo personalizado

Un CompositionSurfaceBrush también se puede usar para pintar un área con píxeles de un ICompositionSurface representado mediante Win2D (o D2D).

En el código siguiente se muestra un SpriteVisual pintado con un fragmento de texto procesado en una ICompositionSurface mediante Win2D. Para usar Win2D con WinUI, instale el paquete NuGet Microsoft.Graphics.Win2D en el proyecto.

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

Del mismo modo, CompositionSurfaceBrush también se puede usar para pintar un SpriteVisual con un SwapChain utilizando la interoperabilidad de Win2D. Este ejemplo muestra cómo usar Win2D para pintar un SpriteVisual con un swapchain.

Pintar con un vídeo

También se puede usar compositionSurfaceBrush para pintar un área con píxeles de un ICompositionSurface representado mediante un vídeo cargado a través de la clase MediaPlayer .

En el código siguiente se muestra un SpriteVisual pintado con un vídeo cargado en un 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 con un efecto de filtro

Un CompositionEffectBrush pinta un área usando el resultado de un CompositionEffect. Los efectos de la capa visual pueden considerarse como efectos de filtro animables aplicados a una colección de contenido de origen, como colores, degradados, imágenes, vídeos, cadenas de intercambio, regiones de la interfaz de usuario o árboles de objetos visuales. El contenido de origen se especifica normalmente mediante otro CompositionBrush.

En la siguiente ilustración y código se muestra un SpriteVisual representado con una imagen de un gato, a la que se ha aplicado un filtro de desaturación.

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 obtener más información sobre cómo crear un efecto mediante CompositionBrushes, vea Efectos en la capa visual.

Pinte con un pincel de composición al que se le haya aplicado una máscara de opacidad

Un CompositionMaskBrush pinta un área con un CompositionBrush con una máscara de opacidad aplicada. La fuente de la máscara de opacidad puede ser cualquier CompositionBrush, ya sea de tipo CompositionColorBrush, CompositionLinearGradientBrush, CompositionSurfaceBrush, CompositionEffectBrush o CompositionNineGridBrush. La máscara de opacidad debe especificarse como compositionSurfaceBrush.

En la siguiente ilustración y código se muestra un SpriteVisual pintado con un CompositionMaskBrush. El origen de la máscara es un compositionLinearGradientBrush que se enmascara para parecerse a un círculo con una imagen 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);

Pintar con un CompositionBrush usando NineGrid stretch

Un CompositionNineGridBrush pinta un área con un CompositionBrush que se extiende utilizando la metáfora de nueve cuadrículas. La metáfora de nueve cuadrículas te permite estirar bordes y esquinas de un CompositionBrush de forma diferente a su centro. La fuente de la extensión de nueve cuadrículas puede ser cualquier CompositionBrush de tipo CompositionColorBrush, CompositionSurfaceBrush o CompositionEffectBrush.

En el código siguiente se muestra un SpriteVisual pintado con CompositionNineGridBrush. La fuente de la máscara es un CompositionSurfaceBrush que se extiende mediante una cuadrícula de Nueve.

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 con píxeles de fondo

Un CompositionBackdropBrush pinta un área con el contenido que está detrás de ella. Un CompositionBackdropBrush nunca se usa por sí mismo, sino que se usa como entrada para otro CompositionBrush como EffectBrush. Por ejemplo, mediante el uso de CompositionBackdropBrush como entrada para un efecto de desenfoque, puede lograr un efecto de vidrio esmerilado.

En el siguiente código se muestra un pequeño árbol visual para crear una imagen usando CompositionSurfaceBrush y una capa de vidrio esmerilado sobre la imagen. La superposición de vidrio esmerilado se crea colocando un SpriteVisual que utiliza un EffectBrush sobre la imagen. EffectBrush usa CompositionBackdropBrush como entrada para el efecto de desenfoque.

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

Combinar CompositionBrushes

Una serie de CompositionBrushes usa otros CompositionBrushes como entradas. Por ejemplo, el método SetSourceParameter se puede utilizar para establecer otro CompositionBrush como entrada para un CompositionEffectBrush. En la tabla siguiente se describen las combinaciones admitidas de CompositionBrushes. Tenga en cuenta que el uso de una combinación no admitida producirá una excepción.

Pincel EffectBrush.SetSourceParameter() PincelDeMáscara.Máscara MaskBrush.Source NineGridBrush.Source
CompositionColorBrush
CompositionLinear
GradientBrush
NO
CompositionSurfaceBrush
CompositionEffectBrush NO NO NO
PincelDeMáscaraDeComposición NO NO NO NO
CompositionNineGridBrush NO
CompositionBackdropBrush NO NO NO

Usar un pincel XAML versus un CompositionBrush

En la siguiente tabla se muestra una lista de escenarios y se indica el uso prescrito de un pincel XAML o Composition al aplicar pintura a un UIElement o un SpriteVisual en su aplicación.

Nota:

Si se sugiere un CompositionBrush para un UIElement XAML, se supone que el CompositionBrush se empaqueta mediante XamlCompositionBrushBase.

Escenario XAML UIElement SpriteVisual de composición
Pintar un área con color sólido SolidColorBrush CompositionColorBrush
Pintar un área con color animado SolidColorBrush CompositionColorBrush
Pintar un área con un degradado estático LinearGradientBrush CompositionLinearGradientBrush
Pintar un área con paradas de degradado animadas CompositionLinearGradientBrush CompositionLinearGradientBrush
Pintar un área con una imagen ImageBrush CompositionSurfaceBrush
Pintar un área con una página web WebView2 N/A
Pintar un área con una imagen mediante el stretch de NineGrid Image Control CompositionNineGridBrush
Pintar un área con la animación de NineGrid stretch CompositionNineGridBrush CompositionNineGridBrush
Pintar un área con una cadena de intercambio SwapChainPanel Interoperabilidad de swapchain con CompositionSurfaceBrush
Pintar un área con un vídeo MediaPlayerElement CompositionSurfaceBrush con interoperabilidad multimedia
Pintar un área con dibujo 2D personalizado CanvasControl desde Win2D Interoperabilidad de CompositionSurfaceBrush con Win2D
Pintar un área usando una máscara que no esté animada Utilice figuras XAML para definir una máscara CompositionMaskBrush
Pintar un área con una máscara animada CompositionMaskBrush CompositionMaskBrush
Pintar un área con un efecto de filtro animado CompositionEffectBrush CompositionEffectBrush
Pintar un área aplicando un efecto a los píxeles de fondo CompositionBackdropBrush CompositionBackdropBrush

Interoperabilidad nativa de la composición entre DirectX y Direct2D con BeginDraw y EndDraw

Interoperabilidad de brochas XAML con XamlCompositionBrushBase