1. 什么是附加属性(attached property )
附加属性依赖属性的一种特殊形式,常见的Grid.Row,Canvas.Left都是附加属性。
///
// 从指定元素获取 Left 依赖项属性的值。
///
/// The element from which the property value is read.
/// Left 依赖项属性的值
public static double GetLeft(DependencyObject obj)
{
return (double)obj.GetValue(LeftProperty);
}
///
/// 将 Left 依赖项属性的值设置为指定元素。
///
/// The element on which to set the property value.
/// The property value to set.
public static void SetLeft(DependencyObject obj, double value)
{
obj.SetValue(LeftProperty, value);
}
///
/// 标识 Left 依赖项属性。
///
public static readonly DependencyProperty LeftProperty =
DependencyProperty.RegisterAttached("Left", typeof(double), typeof(MyCanvas), new PropertyMetadata(0d));
附加属性的简单定义如上述代码所示。可以看出和依赖属性不同的地方在于没有作为属性包装器的Setter和Getter,而多了两个静态函数GetXXX和SetXXX。并且注册标识符使用DependencyProperty.RegisterAttached而不是DependencyProperty.Register。
2. 附加属性有什么作用
和依赖属性不同的地方在于,依赖属性是依赖对象本身的属性,附加属性是附加在其他对象身上的属性,通俗来说就是在别的对象内插入自己的属性。上面提到的Grid.Row,就是Grid将Row属性附加到没有Row属性的其它类中,以便进行布局。
3. 附加属性的使用
附加实行的使用方式和依赖属性十分相似。
在XAML中使用附加属性:
在C#代码中使用附加属性:
button.SetValue(Grid.RowProperty, 1);
4. 完整的自定义附加属性
///
// 从指定元素获取 Left 依赖项属性的值。
///
/// The element from which the property value is read.
/// Left 依赖项属性的值
public static double GetLeft(DependencyObject obj)
{
return (double)obj.GetValue(LeftProperty);
}
///
/// 将 Left 依赖项属性的值设置为指定元素。
///
/// The element on which to set the property value.
/// The property value to set.
public static void SetLeft(DependencyObject obj, double value)
{
obj.SetValue(LeftProperty, value);
}
///
/// 标识 Left 依赖项属性。
///
public static readonly DependencyProperty LeftProperty =
DependencyProperty.RegisterAttached("Left", typeof(double), typeof(MyCanvas), new PropertyMetadata(0d, OnLeftChanged));
private static void OnLeftChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args)
{
double oldValue = (double)args.OldValue;
double newValue = (double)args.NewValue;
if (oldValue == newValue)
return;
}
以上代码为一个相对完整的自定义附加属性,自定义附加属性的步骤如下
-
使用 DependencyProperty.RegisterAttached注册附加属性标识符,标示符的名称必须是PropertyName+"Property",如这个例子中的"LeftProperty"。在PropertyMetadata中指定属性默认值。
-
实现静态的属性访问器函数,名称必须是GetPropertyName 和SetPropertyName,如例子中的public static double GetLeft(DependencyObject obj)和public static void SetLeft(DependencyObject obj, double value)。
-
如果需要监视属性值变更,可以在PropertyMetadata中定义一个PropertyChangedCallback方法,一遍命名方式为OnPropertyNameChanged,如上述例子中的private static void OnLeftChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args)。
注意: 属性访问器中不要有多余的代码,理由参考依赖属性。
VisualStudio自带附加属性的代码段是propa,生成代码如下:
public static int GetMyProperty(DependencyObject obj)
{
return (int)obj.GetValue(MyPropertyProperty);
}
public static void SetMyProperty(DependencyObject obj, int value)
{
obj.SetValue(MyPropertyProperty, value);
}
// Using a DependencyProperty as the backing store for MyProperty. This enables animation, styling, binding, etc...
public static readonly DependencyProperty MyPropertyProperty =
DependencyProperty.RegisterAttached("MyProperty", typeof(int), typeof(ownerclass), new PropertyMetadata(0));
要生成上述例子的完整附加属性代码,可使用自定义的代码段,快捷键是ap:
ap
Expansion
Attached Property
dino.c
For Attached Property
ap
int
int
int
MyProperty
属性名
MyProperty
classname
类名
ClassName()
ClassNamePlaceholder
// 从指定元素获取 $MyProperty$ 依赖项属性的值。
///
/// The element from which the property value is read.
/// $MyProperty$ 依赖项属性的值
public static $int$ Get$MyProperty$(DependencyObject obj)
{
return ($int$)obj.GetValue($MyProperty$Property);
}
///
/// 将 $MyProperty$ 依赖项属性的值设置为指定元素。
///
/// The element on which to set the property value.
/// The property value to set.
public static void Set$MyProperty$(DependencyObject obj, $int$ value)
{
obj.SetValue($MyProperty$Property, value);
}
///
/// 标识 $MyProperty$ 依赖项属性。
///
public static readonly DependencyProperty $MyProperty$Property =
DependencyProperty.RegisterAttached("$MyProperty$", typeof($int$), typeof($classname$), new PropertyMetadata(0,On$MyProperty$Changed));
private static void On$MyProperty$Changed(DependencyObject obj, DependencyPropertyChangedEventArgs args)
{
$classname$ target = obj as $classname$;
$int$ oldValue = ($int$)args.OldValue;
$int$ newValue = ($int$)args.NewValue;
if (oldValue == newValue)
return;
}
]]>