1. 什麼是附加屬性(attached property )
附加屬性依賴屬性的一種特殊形式,常見的Grid.Row,Canvas.Left都是附加屬性。
/// <summary>
// 從指定元素獲取 Left 依賴項屬性的值。
/// </summary>
/// <param name="obj">The element from which the property value is read.</param>
/// <returns>Left 依賴項屬性的值</returns>
public static double GetLeft(DependencyObject obj)
{
return (double)obj.GetValue(LeftProperty);
}
/// <summary>
/// 將 Left 依賴項屬性的值設置爲指定元素。
/// </summary>
/// <param name="obj">The element on which to set the property value.</param>
/// <param name="value">The property value to set.</param>
public static void SetLeft(DependencyObject obj, double value)
{
obj.SetValue(LeftProperty, value);
}
/// <summary>
/// 標識 Left 依賴項屬性。
/// </summary>
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中使用附加屬性:
<StackPanel Grid.Row="1"/>
在C#代碼中使用附加屬性:
button.SetValue(Grid.RowProperty, 1);
4. 完整的自定義附加屬性
/// <summary>
// 從指定元素獲取 Left 依賴項屬性的值。
/// </summary>
/// <param name="obj">The element from which the property value is read.</param>
/// <returns>Left 依賴項屬性的值</returns>
public static double GetLeft(DependencyObject obj)
{
return (double)obj.GetValue(LeftProperty);
}
/// <summary>
/// 將 Left 依賴項屬性的值設置爲指定元素。
/// </summary>
/// <param name="obj">The element on which to set the property value.</param>
/// <param name="value">The property value to set.</param>
public static void SetLeft(DependencyObject obj, double value)
{
obj.SetValue(LeftProperty, value);
}
/// <summary>
/// 標識 Left 依賴項屬性。
/// </summary>
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;
}
以上代碼爲一個相對完整的自定義附加屬性,自定義附加屬性的步驟如下
1. 使用 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:
<?xml version="1.0" encoding="utf-8"?>
<CodeSnippets xmlns="http://schemas.microsoft.com/VisualStudio/2005/CodeSnippet">
<CodeSnippet Format="1.0.0">
<Header>
<Keywords>
<Keyword>ap</Keyword>
</Keywords>
<SnippetTypes>
<SnippetType>Expansion</SnippetType>
</SnippetTypes>
<Title>Attached Property</Title>
<Author>dino.c</Author>
<Description>For Attached Property</Description>
<HelpUrl>
</HelpUrl>
<Shortcut>ap</Shortcut>
</Header>
<Snippet>
<References>
<Reference>
<Assembly>
</Assembly>
</Reference>
</References>
<Declarations>
<Literal Editable="true">
<ID>int</ID>
<ToolTip>int</ToolTip>
<Default>int</Default>
<Function>
</Function>
</Literal>
<Literal Editable="true">
<ID>MyProperty</ID>
<ToolTip>屬性名</ToolTip>
<Default>MyProperty</Default>
<Function>
</Function>
</Literal>
<Literal Editable="false">
<ID>classname</ID>
<ToolTip>類名</ToolTip>
<Function>ClassName()</Function>
<Default>ClassNamePlaceholder</Default>
</Literal>
</Declarations>
<Code Language="csharp">
<![CDATA[
/// <summary>
// 從指定元素獲取 $MyProperty$ 依賴項屬性的值。
/// </summary>
/// <param name="obj">The element from which the property value is read.</param>
/// <returns>$MyProperty$ 依賴項屬性的值</returns>
public static $int$ Get$MyProperty$(DependencyObject obj)
{
return ($int$)obj.GetValue($MyProperty$Property);
}
/// <summary>
/// 將 $MyProperty$ 依賴項屬性的值設置爲指定元素。
/// </summary>
/// <param name="obj">The element on which to set the property value.</param>
/// <param name="value">The property value to set.</param>
public static void Set$MyProperty$(DependencyObject obj, $int$ value)
{
obj.SetValue($MyProperty$Property, value);
}
/// <summary>
/// 標識 $MyProperty$ 依賴項屬性。
/// </summary>
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;
}
]]>
</Code>
</Snippet>
</CodeSnippet>
</CodeSnippets>