概述 UWP Community Toolkit Extensions 中有一個為可視元素提供的擴展 - VisualExtensions,本篇我們結合代碼詳細講解 VisualExtensions 的實現。 VisualExtensions 為可視元素提供了一種簡單的在 XAML 中修改通用屬性的 ...
概述
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 類中,下麵我們先來看看類結構:
首先看一下類中定義的附加屬性:
- AnchorPoint - 獲取或設置 UIElement 的 Visual.AnchorPoint 屬性,string 類型;改變時觸發 OnAnchorPointChanged 事件;
- CenterPoint - 獲取或設置 UIElement 的 Visual.CenterPoint 屬性,string 類型;改變時觸發 OnCenterPointChanged 事件;
- Offset - 獲取或設置 UIElement 的 Visual.Offset 屬性,string 類型;改變時觸發 OnOffsetChanged 事件;
- Opacity - 獲取或設置 UIElement 的 Visual.Opacity 屬性,double 類型;改變時觸發 OnOpacityChanged 事件;
- RotationAngle - 獲取或設置 UIElement 的 Visual.RotationAngle 屬性,double 類型,單位是弧度;改變時觸發 OnRotationAngleChanged 事件;
- RotationAngleInDegrees - 獲取或設置 UIElement 的 Visual.RotationAngleInDegrees 屬性,double 類型,單位是角度;改變時觸發 OnRotationAngleInDegreesChanged 事件;
- RotationAxis - 獲取或設置 UIElement 的 Visual.RotationAxis 屬性,string 類型;改變時觸發 OnRotationAxisChanged 事件;
- Scale - 獲取或設置 UIElement 的 Visual.Scale 屬性,string 類型;改變時觸發 OnScaleChanged 事件;
- Size - 獲取或設置 UIElement 的 Visual.Size 屬性,string 類型;改變時觸發 OnSizeChanged 事件;
- NormalizedCenterPoint - 獲取或設置 UIElement 的 Visual.CenterPoint 屬性在 0.0 - 1.0 之間標準化的值,string 類型;改變時觸發 OnNormalizedCenterPointChanged 事件;
除去 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) 為例來解釋一下:
- 處理前先做一些基本格式的檢查,如長度過短,帶有 <> 字元的情況;
- Split() 方法分割字元串,根據分割後的段數,如果為 1,則使用它創建 Vector2;如果為 2,則使用兩個值創建 Vector2;
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!!!