概述
UWP Community Toolkit Extensions 中有一个为可视元素提供的扩展 - VisualExtensions,本篇我们结合代码详细讲解 VisualExtensions 的实现。
VisualExtensions 为可视元素提供了一种简单的在 XAML 中修改通用属性的方法,这些通用属性包括 AnchorPoint,CenterPoint,Offset,Opacity,RotationAngle,RotationAngleInDegrees,RotationAxis,Scale,Size 和 NormalizedCenterPoint。 接下来看看官方示例的截图:
Doc: https://docs.microsoft.com/zh-cn/windows/uwpcommunitytoolkit/extensions/visualextensions
Namespace: Microsoft.Toolkit.Uwp.UI.Extensions; Nuget: Microsoft.Toolkit.Uwp.UI;
开发过程
代码分析
VisualExtensions 的处理逻辑在 VisualExtensions.cs 类中,下面我们先来看看类结构:
首先看一下类中定义的附加属性:
除去 OnNormalizedCenterPointChanged 事件,其他事件的处理逻辑都是简单的进行了 Set 方法处理,我们来看一下 OnNormalizedCenterPointChanged 的处理:
OnNormalizedCenterPointChanged 的主要处理逻辑在 SetupNormalizedCenterPoint(args, element):
解除 element 的 SizeChanged 事件绑定;把 normalizedValue 转为 Vector3 类型,然后设置 element VIsual 的 CenterPoint,根据 ActualSize 和 normalizedValue 的换算关系;最后重新绑定 element 的 SizeChanged 事件;
private static void SetupNormalizedCenterPoint(DependencyPropertyChangedEventArgs e, FrameworkElement element)
{
element.SizeChanged -= KeepCenteredElementSizeChanged;
if (e.NewValue is string normalizedValue)
{
var vectorValue = normalizedValue.ToVector3();
var visual = GetVisual(element);
visual.CenterPoint = new Vector3((float)element.ActualWidth * vectorValue.X, (float)element.ActualHeight * vectorValue.Y, 0);
element.SizeChanged += KeepCenteredElementSizeChanged;
}
}
来看一下 KeepCenteredElementSizeChanged 事件的处理逻辑,和 SetupNormalizedCenterPoint(args, element) 方法的处理基本相同,都是在使用 normalizedValue 设置 element Visual 的 CenterPoint;
private static void KeepCenteredElementSizeChanged(object sender, SizeChangedEventArgs e)
{
var element = sender as FrameworkElement;
var normalizedValue = GetNormalizedCenterPoint(element);
var vectorValue = normalizedValue.ToVector3();
var visual = GetVisual(element);
visual.CenterPoint = new Vector3((float)element.ActualWidth * vectorValue.X, (float)element.ActualHeight * vectorValue.Y, 0);
}
我们看到很多的属性都是 string 类型,而实际操作中需要用到各种类型的 Vector,要求 string 的格式为 "0,0", "0,0,0", "0,0,0,0" 这样的用逗号隔开的格式,类似 Margin 的格式,来看一下转换的方法:
因为 string 转换为 Vector2 Vector3 和 Vector4 的处理类似,我们以 ToVector2(str) 为例来解释一下:
public static Vector2 ToVector2(this string str)
{
try
{
var strLength = str.Count();
if (strLength < 1)
{
throw new Exception();
}
else if (str[0] == '<' && str[strLength - 1] == '>')
{
str = str.Substring(1, strLength - 2);
}
string[] values = str.Split(',');
var count = values.Count();
Vector2 vector;
if (count == 1)
{
vector = new Vector2(float.Parse(values[0]));
}
else if (count == 2)
{
vector = new Vector2(float.Parse(values[0]), float.Parse(values[1]));
}
else
{
throw new Exception();
}
return vector;
}
catch (Exception)
{
throw new FormatException($"Cannot convert {str} to Vector2. Use format \"float, float\"");
}
}
调用示例
我们给 Border 设置了 Visual Extensions,包括缩放,旋转,透明度等,可以看到运行图中和设置一致;
<Border Height="100"
Width="100"
Background="Purple"
extensions:VisualExtensions.CenterPoint="50,50,0"
extensions:VisualExtensions.Opacity="0.5"
extensions:VisualExtensions.RotationAngleInDegrees="80"
extensions:VisualExtensions.Scale="2, 0.5, 1"
extensions:VisualExtensions.NormalizedCenterPoint="0.5, 0.5, 0" />
总结
到这里我们就把 UWP Community Toolkit Extensions 中的 VisualExtensions 的源代码实现过程和简单的调用示例讲解完成了,希望能对大家更好的理解和使用这个扩展有所帮助。欢迎大家多多交流,谢谢!
最后,再跟大家安利一下 UWPCommunityToolkit 的官方微博:https://weibo.com/u/6506046490, 大家可以通过微博关注最新动态。
衷心感谢 UWPCommunityToolkit 的作者们杰出的工作,Thank you so much, UWPCommunityToolkit authors!!!