附加屬性
附加屬性,大家都不陌生,最常見的是Canvas.Left/Canvas.Top,類似的也有Grid.Row/Grid.Column等附加屬性。舉個最常見的例子
<Canvas> <Ellipse Fill="Red" Width="100" Height="60" Canvas.Left="56" Canvas.Top="98"/> </Canvas>
需要說明的是並不是所有的附加屬性都是元素放進去后才會有附加效果,上面的例子只是剛好是這種錯覺的巧合情況,Grid.Row也屬於這種巧合。
還是舉個反例來說明
<Canvas> <Button Content="Copy" ToolTip="Copy the Selected Items"ToolTipService.ShowOnDisabled="True"/> </Canvas>
ToolTipService類是一個靜態類,和Button風馬牛不相及,兩者之間沒有任何關系。
這就是關於附加屬性DebugLZQ認為需要說明的地方。
為控件添加一個自定義的附加屬性
1.我們有這樣的一個XAML
<Canvas> <Ellipse Fill="Red" Width="100" Height="60" /> <Rectangle Fill="Blue" Width="80" Height="80" Canvas.Left="100" Canvas.Top="100" /> <Button Content="Hello" Canvas.Left="130" Canvas.Top="30" FontSize="20" /> </Canvas>
假如,我們需要實現控件繞中心旋轉一定的角度。通常我們需要寫類似的Rotate
<Ellipse Fill="Red" Width="100" Height="60" RenderTransformOrigin=".5,.5"> <Ellipse.RenderTransform> <RotateTransform Angle="30" /> </Ellipse.RenderTransform> </Ellipse>
當然這樣OK,程序運行沒有問題。
但,缺點是需要寫較多的代碼;當我們需要為頁面其他所有元素實現旋轉時,又需要寫大量類似的代碼。
我們可以通過附加屬性來簡化代碼。如何做呢?
2.為工程添加一個名為RotationManager的類,我們在這個類中添加一個附加屬性,讓其他都能使用這個附加屬性。
我們在類中鍵入"propa"
和依賴屬性類似,連按2次Tab,修改相應命名,如下:
public static double GetAngle(DependencyObject obj) { return (double)obj.GetValue(AngleProperty); } public static void SetAngle(DependencyObject obj, double value) { obj.SetValue(AngleProperty, value); } public static readonly DependencyProperty AngleProperty = DependencyProperty.RegisterAttached("Angle", typeof(double), typeof(RotationManager), new PropertyMetadata(0.0));
這樣我們就完成了附加屬性的定義。
為了能夠在XAML中使用,在XAML中添加如下映射。
<Window x:Class="CreatingAnAttachedProperty.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:CreatingAnAttachedProperty"
這樣,頁面上的元素就可以使用這個附加屬性了,如下:
<Canvas> <Ellipse Fill="Red" Width="100" Height="60" Canvas.Left="56" Canvas.Top="98" local:RotationManager.Angle="30"/> <Rectangle Fill="Blue" Width="80" Height="80" Canvas.Left="285" Canvas.Top="171" local:RotationManager.Angle="45" /> <Button Content="Hello" Canvas.Left="265" Canvas.Top="48" FontSize="20" local:RotationManager.Angle="60"/> </Canvas>
3.此時編輯器,沒有任何旋轉,若我們此時運行程序,也沒有任何的旋轉效果,為什么?因為我們只是添加了一個附加屬性,給它付了個初值,當值改變的時候,我們並沒有添加相應的處理邏輯。
依次,我們需要返回RotationManager.cs添加相應的值改變事件及事件處理邏輯。如下:
public static readonly DependencyProperty AngleProperty = DependencyProperty.RegisterAttached("Angle", typeof(double), typeof(RotationManager), new PropertyMetadata(0.0,OnAngleChanged)); private static void OnAngleChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e) { var element = obj as UIElement; if (element != null) { element.RenderTransformOrigin = new Point(0.5, 0.5); element.RenderTransform = new RotateTransform((double)e.NewValue); } }
添加完成后,我們在編輯器中,看到如下效果:
如果我們運行,則效果如下:
相比於前面挨個挨個的添加Rotate效果,程序是Clearn很多?這就是附加屬性帶來的便利。
完整的RotationManager.cs如下:

using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows; using System.Windows.Media;//necessary namespace CreatingAnAttachedProperty { class RotationManager:DependencyObject { public static double GetAngle(DependencyObject obj) { return (double)obj.GetValue(AngleProperty); } public static void SetAngle(DependencyObject obj, double value) { obj.SetValue(AngleProperty, value); } public static readonly DependencyProperty AngleProperty = DependencyProperty.RegisterAttached("Angle", typeof(double), typeof(RotationManager), new PropertyMetadata(0.0,OnAngleChanged)); private static void OnAngleChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e) { var element = obj as UIElement; if (element != null) { element.RenderTransformOrigin = new Point(0.5, 0.5); element.RenderTransform = new RotateTransform((double)e.NewValue); } } } }
Update:
WPF: Creating parameterized styles with attached properties
Wish it helps.