图形渲染
一、变形
变形操作主要包括了位移、旋转、缩放、斜切、矩阵变换。
- 缩放:这里说的缩放指的是对坐标系的缩放,控件本身的大小并没有变化,只不过是视觉上看起来变大变小了。
- 斜切:斜切的效果类似于矩形在水平方向或垂直方向上向平行四边形变化的过程。
- 矩阵变换:矩阵较为复杂,包含了前面所说的所有变形。
WPF中所有的控件都可以通过LayoutTransform
或RenderTransform
属性来支持变形操作。
LayoutTransform
LayoutTransform
:控件的布局变形属性,在进行变形时,会导致界面布局的重新排列,如果空间不足则无法正确显示。由于会影响其他控件的布局,且界面的重新排列会影响性能,因此LayoutTransform
用的较少。
<Button Content="button2">
<Button.LayoutTransform>
<RotateTransform Angle="45" />
</Button.LayoutTransform>
</Button>
RenderTransform
RenderTransform
:控件的渲染变形属性,在进行变形时,保留原有空间及布局排列,仅变形控件在界面上做对应的变形。
<Button Content="button2">
<Button.RenderTransform>
<RotateTransform Angle="45" />
</Button.RenderTransform>
</Button>
需要注意的是,渲染变形在控件发生变形之后,只是视觉上发生了变化效果,控件的实际空间、实际坐标依旧没有变化。
由于控件的RenderTransform
渲染变形属性在界面布局和性能上较为友好,因此在实际开发中用得较多,接下来也以RenderTransform
为主,进行学习。
1、位移
TranslateTransform
:以控件的左上角为原点进行位移。
<Border Width="100" Height="100" Background="LightBlue">
<Border.RenderTransform>
<TranslateTransform X="20" Y="20"/>
</Border.RenderTransform>
</Border>
2、旋转
RotateTransform
:默认以控件左上角作为中心进行旋转。
Angle
:旋转角度。CenterX
、CenterY
:指定旋转时的中心坐标,以控件左上角为零点进行计算。
<Border Width="100" Height="100" Background="LightBlue">
<Border.RenderTransform>
<RotateTransform Angle="45" CenterX="50" CenterY="50"/>
</Border.RenderTransform>
</Border>
当控件大小随界面大小变化时,使用CenterX
、CenterY
来将旋转中心写死显然是不合适的,WPF为此给每个控件提供了RenderTransformOrigin
属性,该属性可以通过X、Y轴上控件大小的比例值来指定控件旋转时的中心点(默认为0,0)。
<Border Width="100" Height="100" Background="LightBlue" RenderTransformOrigin="0.5,0.5">
<Border.RenderTransform>
<RotateTransform Angle="45"/>
</Border.RenderTransform>
</Border>
3、缩放
ScaleTransform
:以控件左上角为原点按比例进行缩放。
ScaleX
、ScaleY
:缩放比例,1为100%。CenterX
、CenterY
:指定缩放的原点,可以通过控件的RenderTransformOrigin
属性进行指定。
<Border Width="100" Height="100" Background="LightBlue">
<Border.RenderTransform>
<ScaleTransform ScaleX="0.5" ScaleY="0.5"/>
</Border.RenderTransform>
</Border>
4、斜切
SkewTransform
:以控件左上角为原点进行斜切变化。
AngleX
、AngleY
:分别表示在x轴和y轴上的斜切角度。这些角度以度为单位,并且可以为正或负值。正值表示向右倾斜,负值表示向左倾斜。CenterX
、CenterY
:指定斜切的原点,可以通过控件的RenderTransformOrigin
属性进行指定。
<Border Width="100" Height="100" Background="LightBlue" RenderTransformOrigin="0.5,0.5">
<Border.RenderTransform>
<SkewTransform AngleX="20" AngleY="20"/>
</Border.RenderTransform>
</Border>
5、矩阵变换
矩阵变换可以实现上文中的所有变形,只不过某些变形实现起来比较复杂(例如旋转)。
MatrixTransform
:以控件左上角为原点进行矩阵变换。
Matrix
:矩阵变换的参数,可以填入六个值,分别为X轴缩放、X轴倾斜(弧度)、Y轴倾斜(弧度)、Y轴缩放、X轴位移、Y轴位移。- 原点:原点可以通过控件的
RenderTransformOrigin
属性进行设定。 - 通过矩阵变换可以进行将几何形状类型的
RectangleGeometry
变换成平行四边形。
<Border Width="100" Height="100" Background="LightBlue" RenderTransformOrigin="0.5,0.5">
<Border.RenderTransform>
<MatrixTransform Matrix="0.5 0 0 0.5 0 0"/>
</Border.RenderTransform>
</Border>
旋转:矩阵变换的旋转操作相对复杂,需要通过代码进行三角函数运算来实现。
<Border Width="100" Height="100" Background="LightBlue" RenderTransformOrigin="0.5,0.5">
<Border.RenderTransform>
<MatrixTransform Matrix="1 0 0 1 0 0" x:Name="mt"/>
</Border.RenderTransform>
</Border>
public MainWindow()
{
InitializeComponent();
var angle = 45 * Math.PI / 180;
var matrix =new Matrix(
Math.Cos(angle),
Math.Sin(angle),
-Math.Sin(angle),
Math.Cos(angle),
0,0
);
mt.Matrix = matrix;
}
6、组合变形
从变换矩阵的使用中可以看出,矩阵变换是可以对多种变形同时进行的。但矩阵变换在某些变形上又稍显复杂,如果想更加简单明了的实现组合变形,可以使用TransformGroup
元素。
在进行变形组合时,变形的操作顺序会影响最终结果,因此需要注意使用合理的变形顺序。
<Border Width="100" Height="100" Background="LightBlue" RenderTransformOrigin="0.5 0.5">
<Border.RenderTransform>
<TransformGroup>
<TranslateTransform X="20" Y="20"/>
<RotateTransform Angle="45"/>
<ScaleTransform ScaleX="0.8" ScaleY="0.8"/>
</TransformGroup>
</Border.RenderTransform>
</Border>
二、画刷
所有的Brush
类型对象都可以使用画刷进行渲染,例如Backround
、Fill
、Stroke
等属性都是Brush
类型。
1、单色画刷
SolidColorBrush
:单色画刷(纯色画刷),使用纯色绘制区域,效果等同于直接在空间中设置Background="颜色"
。
Background="颜色"
起始就是使用了类型转换器,将值转成了SolidColorBrush
类型对象。
<Border Width="100" Height="100">
<Border.Background>
<SolidColorBrush Color="LightBlue"/>
</Border.Background>
</Border>
2、线性渐变画刷
LinearGradientBrush
:线性渐变画刷,使用线性渐变绘制区域。
StartPoint
、EndPont
:这两个属性决定了颜色渐变的方向。分别传入两个值,表示所在控件在X轴、Y轴上比例,从而决定从哪个点开始向哪个点发生颜色的渐变。GradientStop
:用于描述渐变中,转换点的位置和颜色,可以向LinearGradientBrush
中放入多个描述,形成多种颜色的渐变。Color
:设置渐变的目标颜色。Offset
:传入一个数值,表示在渐变路径上的比例来确定目标颜色渐变完成时的起始位置。
<Border Width="100" Height="100">
<Border.Background>
<LinearGradientBrush StartPoint="0,1" EndPoint="1,0">
<GradientStop Color="LightBlue" Offset="0"/>
<GradientStop Color="CadetBlue" Offset="0.5"/>
<GradientStop Color="CornflowerBlue" Offset="1"/>
</LinearGradientBrush>
</Border.Background>
</Border>
3、径向渐变
RadialGradientBrush
:使用径向渐变绘制区域,焦点定义渐变的开始,而圆定义渐变的终点。(不是很明白,感觉像是从中心点向四周辐射渐变)
GradientOrigin
:梯度的二维焦点的位置,默认为0.5 0.5(也就是区域中心点),设定渐变的起始点。Center
:设置径向渐变的中心点,默认也是0.5 0.5。中心点跟焦点是有区别的,焦点决定了渐变的起始点,中心点决定了渐变的径向渐变的中心。GradientStop
:用于描述渐变中,转换点的位置和颜色,可以向RadialGradientBrush
中放入多个描述,形成多种颜色的渐变。Color
:设置渐变的目标颜色。Offset
:传入一个数值,表示在渐变路径上的比例来确定目标颜色渐变完成时的起始位置。
<Border Width="150" Height="100">
<Border.Background>
<RadialGradientBrush GradientOrigin="1 0.5" Center="0.5 0.5">
<GradientStop Color="LightBlue" Offset="0"/>
<GradientStop Color="CadetBlue" Offset="0.965"/>
<GradientStop Color="CornflowerBlue" Offset="0.965"/>
</RadialGradientBrush>
</Border.Background>
</Border>
4、图像画刷
ImageBrush
:使用图像绘制区域。
ImageSource
:指定使用的图像资源。Stretch
:拉伸方式。- 图像画刷最大的特点在于,不会影响控件容器的布局与使用。比如
Border
控件本来只能布局一个子控件的,这个时候如果通过Image
控件来添加图像,则无法在Border
中再去使用其他子控件。而通过ImageBrush
来添加图像后,还可以继续使用其他子控件。
<Border Width="150" Height="100">
<Border.Background>
<ImageBrush ImageSource="/WpfApp5;component/Images/1-1.bmp"/>
</Border.Background>
<TextBlock Text="居然可以多放一个控件"/>
</Border>
5、绘制画刷
DrawingBrush
:绘制区域,该对象包括形状、文本、视频、图像或其他绘制项。
TileMode
:填充方式。Viewport
:调整绘制图形的视口大小和位置,可以填入四个值,分别表示绘制图形X轴和Y轴上的位移、视口在X轴上的长度、视口在Y轴上的长度。- 视口指的是绘制图像的最小外接矩形区域,也就是用来绘制的区域。
ViewportUnits
:指定Viewport
的设定是否是相对于输出区域的大小。一般为Absolute
,即相对于图形所在容器的左上角。
通过DrawingBrush
,可以画出简单的图形后通过填充模式来铺满整个背景,而不需要一笔一笔的去画满背景。
<Border Height="50">
<Border.Background>
<DrawingBrush TileMode="FlipX" ViewportUnits="Absolute" Viewport="0,0,10,20">
<DrawingBrush.Drawing>
<GeometryDrawing>
<GeometryDrawing.Pen>
<!--这里设定画笔的颜色和粗细-->
<Pen Brush="Gray" Thickness="1"/>
</GeometryDrawing.Pen>
<GeometryDrawing.Geometry>
<GeometryGroup>
<LineGeometry StartPoint="0,0" EndPoint="0,20"/>
<LineGeometry StartPoint="0,20" EndPoint="20,20"/>
</GeometryGroup>
</GeometryDrawing.Geometry>
</GeometryDrawing>
</DrawingBrush.Drawing>
</DrawingBrush>
</Border.Background>
</Border>
6、视觉画刷
VisualBrush
:将指定控件(继承了Visual的控件)上的视觉效果渲染到当前控件中。
- 几个常用属性与
DrawingBrush
一样。 Visual
:渲染源- 视觉上的渲染并不会对控件本身的布局有影响。
- 渲染源控件的视觉效果是怎么样的,视觉画刷渲染后就是怎么样的。如果源控件发生变化,视觉渲染也会同步发生变化。
<StackPanel>
<TextBlock Text="渲染源" Name="tb"/>
<Border Height="25" Width="50" BorderThickness="2" BorderBrush="red" HorizontalAlignment="Left">
<Border.Background>
<VisualBrush Visual="{Binding ElementName=tb}"/>
</Border.Background>
</Border>
</StackPanel>
<Grid Grid.Column="1" Grid.Row="1">
<Grid.Background>
<VisualBrush Viewport="0,0,100,60" ViewportUnits="Absolute" TileMode="Tile">
<VisualBrush.Visual>
<Path Data="M18 60,0 30,18 0 50,0 69,30 50,60M69,30 100,30" Stroke="Orange" StrokeThickness="1"/>
</VisualBrush.Visual>
</VisualBrush>
</Grid.Background>
<Grid.OpacityMask>
<RadialGradientBrush>
<GradientStop Color="Black" Offset="0"/>
<GradientStop Color="Transparent" Offset="1"/>
</RadialGradientBrush>
</Grid.OpacityMask>
</Grid>
7、位映射缓存画刷
BitmapCacheBrush
:将指定控件上的原始视觉效果渲染到当前控件中。
Target
:渲染源。RenderAtScale
:可以理解为渲染的像素百分比0-1表示百分之0到百分之百,2为百分之两百,数值越小越模糊。
BitmapCacheBrush
与VisualBrush
有区别的,BitmapCacheBrush 会将绑定的可视元素渲染为位图并缓存。这意味着它只会在第一次使用时进行渲染,后续使用时会直接使用缓存的位图。适合需要重复使用相同视觉内容的场景,尤其是在性能敏感的情况下
<TextBlock Text="渲染源" Name="tb">
<TextBlock.Effect>
<BlurEffect Radius="2"/>
</TextBlock.Effect>
</TextBlock>
<Border Height="25" Width="50" BorderThickness="2" BorderBrush="red" HorizontalAlignment="Left">
<Border.Background>
<VisualBrush Visual="{Binding ElementName=tb}"/>
</Border.Background>
</Border>
<Border Height="25" Width="50" BorderThickness="2" BorderBrush="Yellow" HorizontalAlignment="Left">
<Border.Background>
<BitmapCacheBrush Target="{Binding ElementName=tb}">
<BitmapCacheBrush.BitmapCache>
<BitmapCache RenderAtScale="2"/>
</BitmapCacheBrush.BitmapCache>
</BitmapCacheBrush>
</Border.Background>
</Border>
三、Effect视觉效果
Effect
是UIElement
中的属性成员,为Effect
类型对象,WPF所有的控件都继承了UIElement
,因此都可以对Effect
属性进行设置。
Effect
属性用于设置控件在界面上的视觉效果,具体可以进行视觉模糊(BlurEffect
类型)、阴影(DropShadowEffect
类型)、着色效果(ShaderEffect
类型,不怎么用)等设置。
1、模糊
BlurEffect
:用于设置模糊效果的Effect
类型
Radius
:设置控件的模糊程度,数值越低越模糊。
<TextBlock Text="测试一下模糊" HorizontalAlignment="Center">
<TextBlock.Effect>
<BlurEffect Radius="2"/>
</TextBlock.Effect>
</TextBlock>
2、阴影
DropShadowEffect
:用于设置阴影效果的Effect类型。
Color
:阴影颜色。ShadowDepth
:阴影的深度,即阴影向投射方向移动的距离。(受Direction
影响)BlurRadius
:阴影的模糊程度,数值越大越模糊。Direction
:阴影的投射方向,以正右方为0,逆时针360度旋转。Opacity
:阴影的透明程度,0为完全透明、1为不透明。
<TextBlock Text="测试一下阴影" HorizontalAlignment="Center">
<TextBlock.Effect>
<DropShadowEffect Color="Blue" ShadowDepth="5" BlurRadius="10" Direction="0" Opacity="0.5"/>
</TextBlock.Effect>
</TextBlock>
3、实例
在设置模糊效果时,不必拘泥于针对BlurEffect
或DropShadowEffect
属性来进行设置,可以直接通过绑定Effect
对象来完成设置。
定义绑定的属性
public class LoginViewModel:BindableBase
{
......
private bool isLoading = false;
public bool IsLoading
{
get { return isLoading; }
set
{
SetProperty(ref isLoading, value);
}
}
......
}
定义转换器
通过转换器,来接收绑定属性,根据属性来返回null
或对应的BlurEffect
对象
public class Bool2BlurConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
bool result = false;
if (value != null && bool.TryParse(value.ToString(), out result))
{
if (result)
{
return new BlurEffect() { Radius = 10 };
}
}
return null;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
xaml中设置模糊
<Window ......
xmlns:base="clr-namespace:Client.Base"
......>
<Window.Resources>
......
<base:Bool2BlurConverter x:Key="Bool2BlurConverter"/>
......
</Window.Resources>
<Grid>
<Grid Effect="{Binding IsLoading, Converter={StaticResource Bool2BlurConverter}}">
......
</Grid>
</Grid>
</Window>