[UWP]附加屬性1:概述

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中指定屬性默認值。

  1. 實現靜態的屬性訪問器函數,名稱必須是GetPropertyName 和SetPropertyName,如例子中的public static double GetLeft(DependencyObject obj)和public static void SetLeft(DependencyObject obj, double value)。

  2. 如果需要監視屬性值變更,可以在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>
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章