[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中指定属性默认值。

  2. 实现静态的属性访问器函数,名称必须是GetPropertyName 和SetPropertyName,如例子中的public static double GetLeft(DependencyObject obj)和public static void SetLeft(DependencyObject obj, double value)。

  3. 如果需要监视属性值变更,可以在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>
posted @ 2017-02-18 14:21 dino.c 阅读(...) 评论(...) 编辑 收藏