合成画笔

UWP 应用程序中屏幕上可见的所有内容都可见,因为它由画笔绘制。 画笔使你能够绘制用户界面(UI)对象,其内容范围从简单、纯色到图像或绘图,到复杂的效果链。 本主题介绍使用 CompositionBrush 进行绘画的概念。

请注意,使用 XAML UWP 应用时,你可以选择使用 XAML 画笔CompositionBrush 绘制 UIElement。 通常,如果你的方案受 XAML 画笔支持,则选择 XAML 画笔会更容易且建议选择 XAML 画笔。 例如,对按钮的颜色进行动画处理,更改带有图像的文本或形状的填充。 另一方面,如果你尝试的操作不支持 XAML 画笔,如使用动画蒙板或动画九网格拉伸或效果链绘制,则可以选择 CompositionBrush 以使用 XamlCompositionBrushBase 绘制 UIElement。

使用视觉层时,必须使用 CompositionBrush 绘制 SpriteVisual 的区域

先决条件

此概述假定你熟悉基本合成应用程序的结构,如视觉层概述中所述

使用 CompositionBrush 绘制

CompositionBrush“绘制”其输出的区域。 不同画笔具有不同类型的输出。 某些画笔使用纯色绘制区域,另一些画笔使用渐变、图像、自定义绘图或效果绘制区域。 还有一些专用画笔可以修改其他画笔的行为。 例如,不透明度掩码可用于控制 CompositionBrush 绘制的区域,或者 9 网格可用于控制绘制区域时应用于 CompositionBrush 的拉伸。 CompositionBrush 可以是以下类型之一:

详细信息 引入
CompositionColorBrush 用纯色绘制区域 Windows 10,版本 1511 (SDK 10586)
CompositionSurfaceBrush 用 ICompositionSurface 的内容 绘制区域 Windows 10,版本 1511 (SDK 10586)
CompositionEffectBrush 使用合成效果的内容绘制区域 Windows 10,版本 1511 (SDK 10586)
CompositionMaskBrush 使用具有不透明度掩码的 CompositionBrush 绘制视觉对象 Windows 10,版本 1607 (SDK 14393)
CompositionNineGridBrush 使用 NineGrid 拉伸绘制包含 CompositionBrush 的区域 Windows 10,版本 1607 (SDK 14393)
CompositionLinearGradientBrush 绘制具有线性渐变的区域 Windows 10,版本 1709 (SDK 16299)
CompositionRadialGradientBrush 使用径向渐变绘制区域 Windows 10,版本 1903 (Insider Preview SDK)
CompositionBackdropBrush 通过直接在桌面上的应用程序窗口后面对应用程序的背景像素采样或像素来绘制区域。 用作另一个 CompositionBrush 的输入,例如 CompositionEffectBrush Windows 10,版本 1607 (SDK 14393)

使用纯色绘制

CompositionColorBrush 绘制具有纯色的区域。 可通过多种方式指定 SolidColorBrush 的颜色。 例如,可以指定其 alpha、红色、蓝色和绿色(ARGB)通道,或使用 Colors 类提供的预定义颜色之一。

下图和代码显示了一个小可视化树,用于创建用黑色画笔绘制的矩形,并使用具有颜色值的纯色画笔绘制0x9ACD32。

CompositionColorBrush

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

_compositor = Window.Current.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);

使用线性渐变绘制

CompositionLinearGradientBrush 绘制具有线性渐变的区域。 线性渐变在一根线条(渐变轴)中混合了两种或更多颜色。 使用 GradientStop 对象指定渐变中的颜色及其位置。

下图和代码显示了一个 SpriteVisual,使用红色和黄色以 2 个停止点绘制的 LinearGradientBrush。

CompositionLinearGradientBrush

Compositor _compositor;
SpriteVisual _gradientVisual;
CompositionLinearGradientBrush _redyellowBrush;

_compositor = Window.Current.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 对象用于定义颜色及其在渐变中的位置。

下面的插图和代码显示了使用带有 2 个 GradientStops 的 RadialGradientBrush 绘制的 SpriteVisual。

CompositionRadialGradientBrush

Compositor _compositor;
SpriteVisual _gradientVisual;
CompositionRadialGradientBrush RGBrush;

_compositor = Window.Current.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 可用于使用 LoadedImageSurface API 绘制呈现到 ICompositionSurface 图面 上的图像的区域。

下图和代码显示了使用 LoadedImageSurface 呈现到 ICompositionSurface 上的 licorice 位图绘制的 SpriteVisual。 CompositionSurfaceBrush 的属性可用于拉伸和对齐视觉对象边界内的位图。

CompositionSurfaceBrush

Compositor _compositor;
SpriteVisual _imageVisual;
CompositionSurfaceBrush _imageBrush;

_compositor = Window.Current.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 还可用于绘制使用 Win2D(或 D2D)呈现的 ICompositionSurface 中的像素的区域。

以下代码演示使用 Win2D 呈现到 ICompositionSurface 上的文本运行绘制的 SpriteVisual。 请注意,若要使用 Win2D,需要将 Win2D NuGet 包包含在项目中。

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

_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 还可用于使用 Win2D 互操作通过交换链绘制 SpriteVisual。 此示例 提供了如何使用 Win2D 通过交换链绘制 SpriteVisual 的示例。

使用视频绘制

CompositionSurfaceBrush 还可用于绘制使用通过 MediaPlayer 类加载的视频呈现的 ICompositionSurface 中的像素的区域。

以下代码显示了一个 SpriteVisual,该视频加载到 ICompositionSurface 上。

Compositor _compositor;
SpriteVisual _videoVisual;
CompositionSurfaceBrush _videoBrush;

// MediaPlayer set up with a create from URI

_mediaPlayer = new MediaPlayer();

// Get a source from a URI. This could also be from a file via a picker 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 输出的区域。 视觉层中的效果可以视为应用于源内容的集合(如颜色、渐变、图像、视频、交换链、UI 区域或视觉对象树)的可动画筛选效果。 源内容通常使用另一个 CompositionBrush 指定。

下图和代码显示了用应用了反饱和筛选器效果的猫的图像绘制的 SpriteVisual。

CompositionEffectBrush

Compositor _compositor;
SpriteVisual _effectVisual;
CompositionEffectBrush _effectBrush;

_compositor = Window.Current.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 区域。 不透明度掩码的来源可以是 CompositionColorBrush、CompositionLinearGradientBrush、CompositionSurfaceBrush、CompositionEffectBrush 或 CompositionNineGridBrush 类型的 CompositionBrush。 不透明度掩码必须指定为 CompositionSurfaceBrush。

下图和代码显示了用 CompositionMaskBrush 绘制的 SpriteVisual。 掩码的源是 CompositionLinearGradientBrush,它被屏蔽为使用圆形图像作为掩码的圆。

CompositionMaskBrush

Compositor _compositor;
SpriteVisual _maskVisual;
CompositionMaskBrush _maskBrush;

_compositor = Window.Current.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);

使用 NineGrid 拉伸绘制 CompositionBrush

CompositionNineGridBrush 绘制使用九网格隐喻拉伸的 CompositionBrush 区域。 通过九网格隐喻,可以拉伸 CompositionBrush 的边缘和角落与其中心不同。 9 网格拉伸的源可以由 CompositionColorBrush、CompositionSurfaceBrush 或 CompositionEffectBrush 类型的任何 CompositionBrush 提供。

以下代码显示了用 CompositionNineGridBrush 绘制的 SpriteVisual。 掩码的来源是 CompositionSurfaceBrush,它使用九网格拉伸。

Compositor _compositor;
SpriteVisual _nineGridVisual;
CompositionNineGridBrush _nineGridBrush;

_compositor = Window.Current.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"));
_nineGridBrush.Source = _compositor.CreateSurfaceBrush(_imageSurface);

// set Nine-Grid Insets

_ninegridBrush.SetInsets(1, 5, 10, 20);

// set appropriate Stretch on SurfaceBrush for Center of Nine-Grid

sourceBrush.Stretch = CompositionStretch.Fill;

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

使用背景像素绘制

CompositionBackdropBrush 使用区域后的内容绘制区域。 CompositionBackdropBrush 本身从未使用过,而是用作另一个 CompositionBrush(如 EffectBrush)的输入。 例如,通过使用 CompositionBackdropBrush 作为模糊效果的输入,可以实现霜化玻璃效果。

下面的代码显示了一个小可视化树,用于使用 CompositionSurfaceBrush 和图像上方的霜化玻璃覆盖来创建图像。 霜化玻璃覆盖是通过放置填充图像上方 EffectBrush 的 SpriteVisual 来创建的。 EffectBrush 使用 CompositionBackdropBrush 作为模糊效果的输入。

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

_compositor = Window.Current.Compositor;

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

// Create _imageVisual and add it to the bottom of the container visual.
// Paint the visual with an image.

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 containerVisual.
// Paint the visual with an EffectBrush that applies blur to the content
// underneath the Visual to create a frosted glass effect.

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 = _licoriceBrush;
_backdropVisual.Size = new Vector2(78, 78);
_backdropVisual.Offset = new Vector3(39, 39, 0);
_containerVisual.Children.InsertAtTop(_backdropVisual);

组合 CompositionBrushes

许多 CompositionBrushes 使用其他 CompositionBrushes 作为输入。 例如,可以使用 SetSourceParameter 方法将另一个 CompositionBrush 设置为 CompositionEffectBrush 的输入。 下表概述了 CompositionBrushes 支持的组合。 请注意,使用不受支持的组合将引发异常。

Brush EffectBrush.SetSourceParameter() MaskBrush.Mask MaskBrush.Source NineGridBrush.Source
CompositionColorBrush
CompositionLinear
GradientBrush
NO
CompositionSurfaceBrush
CompositionEffectBrush NO NO
CompositionMaskBrush NO NO NO NO
CompositionNineGridBrush NO
CompositionBackdropBrush NO NO

使用 XAML 画笔与 CompositionBrush

下表提供了方案列表,以及在应用程序中绘制 UIElement 还是 SpriteVisual 时是否规定 XAML 或合成画笔使用。

注意

如果为 XAML UIElement 建议 CompositionBrush,则假定 CompositionBrush 是使用 XamlCompositionBrushBase 打包的。

场景 XAML UIElement 合成 SpriteVisual
用纯色绘制区域 SolidColorBrush CompositionColorBrush
绘制具有动画颜色的区域 SolidColorBrush CompositionColorBrush
使用静态渐变绘制区域 LinearGradientBrush CompositionLinearGradientBrush
绘制具有动画渐变停止点的区域 CompositionLinearGradientBrush CompositionLinearGradientBrush
使用图像绘制区域 ImageBrush CompositionSurfaceBrush
使用网页绘制区域 WebViewBrush 空值
使用 NineGrid 拉伸绘制具有图像的区域 图像控件 CompositionNineGridBrush
使用动画的 NineGrid 拉伸绘制区域 CompositionNineGridBrush CompositionNineGridBrush
使用交换链绘制区域 SwapChainPanel CompositionSurfaceBrush w/ swapchain interop
使用视频绘制区域 MediaElement CompositionSurfaceBrush w/ media interop
使用自定义 2D 绘图绘制区域 Win2D 的 CanvasControl CompositionSurfaceBrush w/ Win2D 互操作
使用非动画掩码绘制区域 使用 XAML 形状 定义掩码 CompositionMaskBrush
使用动画掩码绘制区域 CompositionMaskBrush CompositionMaskBrush
使用动画筛选效果绘制区域 CompositionEffectBrush CompositionEffectBrush
绘制应用于背景像素的效果的区域 CompositionBackdropBrush CompositionBackdropBrush

使用 BeginDraw 和 EndDraw 合成本机 DirectX 和 Direct2D 互操作

XAML 画笔与 XamlCompositionBrushBase 互操作