WPF知识4 依赖属性

依赖项属性是通过调用 Register 方法(或 RegisterReadOnly)在 WPF 属性系统中注册,并通过 DependencyProperty 标识符字段备份的属性。 依赖项属性只能由 DependencyObject 类型使用,但 DependencyObject 在 WPF 类层次结构中的级别很高,因此,WPF 中的大多数可用类都支持依赖项属性。

我们大部分时间都会使用依赖属性,依赖项属性提供用来扩展属性功能的功能,这与字段支持的属性相反。 每个这样的功能通常都表示或支持整套 WPF 功能中的特定功能:

资源

<DockPanel.Resources>
  <SolidColorBrush x:Key="MyBrush" Color="Gold"/>
</DockPanel.Resources>
<Button Background="{DynamicResource MyBrush}" Content="I am gold" />

数据绑定

<Button Content="{Binding XPath=Team/@TeamName}"/>

样式

<Style x:Key="GreenButtonStyle">
  <Setter Property="Control.Background" Value="Green"/>
</Style>
<Button Style="{StaticResource GreenButtonStyle}">I am green!</Button>

动画

<Button>I am animated
  <Button.Background>
    <SolidColorBrush x:Name="AnimBrush"/>
  </Button.Background>
  <Button.Triggers>
    <EventTrigger RoutedEvent="Button.Loaded">
      <BeginStoryboard>
        <Storyboard>
          <ColorAnimation
            Storyboard.TargetName="AnimBrush" 
            Storyboard.TargetProperty="(SolidColorBrush.Color)"
            From="Red" To="Green" Duration="0:0:5" 
            AutoReverse="True" RepeatBehavior="Forever" />
        </Storyboard>
      </BeginStoryboard>
    </EventTrigger>
  </Button.Triggers>
</Button>

元数据重写

public class SpinnerControl : ItemsControl
{
    static SpinnerControl()
    {
        DefaultStyleKeyProperty.OverrideMetadata(
            typeof(SpinnerControl), 
            new FrameworkPropertyMetadata(typeof(SpinnerControl))
        );
    }
}

属性值继承

<StackPanel Canvas.Top="50" DataContext="{Binding Source={StaticResource XmlTeamsSource}}">
  <Button Content="{Binding XPath=Team/@TeamName}"/>
</StackPanel>

button的content属性值继承了stackpanel的datacontext源


 

 

虽然我们大部分时间都是使用依赖属性来做以上事情,仍然很多时候我们要创建自己的依赖属性,显然,自定义的WPF的控件库,及时不需要动画,数据绑定功能时候我们仍然需要创建自己的依赖属性。创建依赖属性很特殊和普通的.NET属性创建完全不同。

需要声明的是:只能为依赖对象添加依赖属性(继承自)DependencyObject,WPF基础结构大部分都继承自这个类。

自定义依赖项属性

首先,属性所在的类要直接或间接继承DependencyObject。这个类生成的对象表示一个具有依赖项属性的对象,这些对象,都能享用WPF的属性系统(属性系统主要是计算属性的值,并提供有关值已更改的系统通知)方面的服务。这个类有两个比较重要的方法,GetValue(返回当前对象依赖项属性的当前有效值)和SetValue(设置依赖项属性的本地值)。

其实,属性对应的字段必需是公有,静态,只读的,类型为DependencyProperty。即public static readonly DependencyProperty 字段名,同时字段的命名也有规范,属性名+Property,字段在定义时,通过DependencyProperty.Register来实注册属性(只有注册了,才能使用WPF属性系统的服务)。

Register方法有三种重载,如下:

名称

说明

Register(String, Type, Type)

使用指定的属性名称、属性类型和属性所在对象的类型。

Register(String, Type, Type, PropertyMetadata)

使用指定的属性名称、属性类型、属性所在对象的类型和属性元数据注册依赖项属性。

Register(String, Type, Type, PropertyMetadata, ValidateValueCallback)

使用指定的属性名称、属性类型、属性所在对象的类型、属性元数据和属性的值验证回调来注册依赖项属性。

Register中,各个参数解释如下:

String:依赖属性的名字(不加Property,即字段的名字);

Type:属性的类型;

Type:属性所属对象的类型;

PropertyMetadata:依赖项对象的属性元数据,是一个PropertyMetadata类型,可能赋初始值。PropertyMetadata有一个object的构造函数;

ValidateValueCallback:表示用作回调的方法,这个类型是一个委托,用于验证依赖项属性的值的有效性,因为是委托,故它的构造参数为一个方法名。

  下面是2个开源自定义控件库的代码:分别是两种特殊的button

    public class AppBarButton : Button
    {
        public AppBarButton()
        {
            DefaultStyleKey = typeof (AppBarButton);
        }

        public static readonly DependencyProperty MetroImageSourceProperty =
            DependencyProperty.Register("MetroImageSource", typeof(Visual), typeof(AppBarButton), new PropertyMetadata(default(Visual)));

        public Visual MetroImageSource
        {
            get { return (Visual)GetValue(MetroImageSourceProperty); }
            set { SetValue(MetroImageSourceProperty, value); }
        }
    }

 

    public class Tile : Button
    {
        public Tile()
        {
            DefaultStyleKey = typeof (Tile);
        }

        public static readonly DependencyProperty TitleProperty = DependencyProperty.Register("Title", typeof(string), typeof(Tile), new PropertyMetadata(default(string)));

        public string Title
        {
            get { return (string)GetValue(TitleProperty); }
            set { SetValue(TitleProperty, value); }
        }

        public static readonly DependencyProperty CountProperty = DependencyProperty.Register("Count", typeof(string), typeof(Tile), new PropertyMetadata(default(string)));

        public string Count
        {
            get { return (string)GetValue(CountProperty); }
            set { SetValue(CountProperty, value); }
        }

        public static readonly DependencyProperty KeepDraggingProperty = DependencyProperty.Register("KeepDragging", typeof(bool), typeof(Tile), new PropertyMetadata(true));

        public bool KeepDragging
        {
            get { return (bool)GetValue(KeepDraggingProperty); }
            set { SetValue(KeepDraggingProperty, value); }
        }
        
        public static readonly DependencyProperty TiltFactorProperty =
            DependencyProperty.Register("TiltFactor", typeof(int), typeof(Tile), new PropertyMetadata(5));

        public int TiltFactor
        {
            get { return (Int32)GetValue(TiltFactorProperty); }
            set { SetValue(TiltFactorProperty, value); }
        }
    }

大致如下:

定义依赖属性并且注册依赖属性,根据约定,定义的依赖属性名称在普通属性末尾加上单词“Property”,完成注册后,添加属性包装器,使用DependencyObject的GetValue方法和SetValue方法。

创建依赖属性就完成了。


 

 

属性验证

wpf使用两种方法用于阻止非法值:

1,ValidateValueCallback 委托:
原型:
public delegate bool ValidateValueCallback(
	Object value
)
true ,如果该值验证; false ,如果已提交的值无效。
例子:
        private static bool ShirtValidateCallback(object value)
        {
            ShirtTypes sh = (ShirtTypes) value;
            return (sh==ShirtTypes.None || sh == ShirtTypes.Bowling || sh == ShirtTypes.Dress || sh == ShirtTypes.Rugby || sh == ShirtTypes.Tee);

        }
2,CoerceValue方法:略

http://msdn.microsoft.com/zh-cn/library/system.windows.dependencyobject.coercevalue.aspx
posted @ 2013-04-02 15:02  xiepeixing  阅读(363)  评论(0编辑  收藏  举报