原文:
WPF QuickStart系列之附加属性(Attached Property)
这一篇博客是关于如何使用附加属性和创建自定义附加属性的。
1. 附加属性使用,
WPF中对附加属性使用最多的莫过于对控件布局时设置控件的位置,例如在Canvas中有一个Rectangle, Ellipse, Button,我们需要设置它们的位置,
<Canvas> <Rectangle x:Name="_rect" Fill="LightBlue" Width="100" Height="50" Canvas.Left="200" Canvas.Top="50"/> <Ellipse Width="100" Height="100" Fill="LightCoral" Canvas.Left="150" Canvas.Top="200"/> <Button Content="I am a button" Width="100" Height="35" Canvas.Left="50" Canvas.Bottom="50"/> </Canvas>
除了在XAML中设置依赖属性外,也可以在C#代码中设置,例如:
Canvas.SetLeft(_rect, 100); Canvas.SetTop(_rect, 50);
显示效果:
附加属性使用起来非常简单。
2. 自定义附加属性
现在有这样一个需求,需要将上面的Button,Ellipse,Rectangle旋转一定角度。我们可以这样来实现:
XAML:
<Canvas> <Rectangle x:Name="_rect" Fill="LightBlue" Width="100" Height="50" Canvas.Top="100" RenderTransformOrigin=".5,.5"> <Rectangle.RenderTransform> <RotateTransform Angle="45"/> </Rectangle.RenderTransform> </Rectangle> <Ellipse Width="150" Height="100" Fill="LightCoral" Canvas.Left="150" Canvas.Top="100" RenderTransformOrigin=".5,.5"> <Ellipse.RenderTransform> <RotateTransform Angle="60"/> </Ellipse.RenderTransform> </Ellipse> <Button Content="I am a button" Width="100" Height="35" Canvas.Left="50" Canvas.Bottom="50" RenderTransformOrigin=".5,.5"> <Button.RenderTransform> <RotateTransform Angle="160"/> </Button.RenderTransform> </Button> </Canvas>
效果如下:
细心的你已经发现上面的三段代码基本一样,而且还挺长的。我们可以使用附加属性来实现,新建一个RotationHelper类,代码如下:
using System.Windows; using System.Windows.Media; namespace UseAttachedProperty.Helper { public class RotationHelper : 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("AngleProperty", typeof(double), typeof(RotationHelper), new PropertyMetadata(0.0,OnAngleChanged)); private static void OnAngleChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { UIElement element = d as UIElement; if(element != null) { element.RenderTransformOrigin = new Point(0.5, 0.5); element.RenderTransform = new RotateTransform((double)e.NewValue); } } } }
将RotationHelper类继承DependencyObject,这样不光Button,Ellipse,可以使用,其他继承自DependencyObject的元素均可使用。
现在在XAML中使用自定义Angle附加属性。
<Window x:Class="UseAttachedProperty.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:helper="clr-namespace:UseAttachedProperty.Helper" xmlns:local="clr-namespace:UseAttachedProperty" mc:Ignorable="d" Title="MainWindow" Height="350" Width="525"> <Canvas> <Rectangle x:Name="_rect" Fill="LightBlue" Width="100" Height="50" Canvas.Top="100" helper:RotationHelper.Angle="45" /> <Ellipse Width="150" Height="100" Fill="LightCoral" Canvas.Left="150" Canvas.Top="100" helper:RotationHelper.Angle="60" /> <Button Content="I am a button" Width="100" Height="35" Canvas.Left="50" Canvas.Bottom="50" helper:RotationHelper.Angle="160" /> </Canvas> </Window>
此时显示效果和上面通过XAML中使用RenderTransform一样。
感谢您的阅读。代码点击这里下载。
PS:目前在工作中,
1. 给TextBox和PasswordBox设置水印文字时,使用到自定义附加属性,示例代码下载;
2. 在WPF MVVM模式下,需要直接绑定PasswordBox的Password属性时是不可以的,因为Password属性不是依赖属性,此时使用自定义附加属性解决了这个问题。示例代码下载。