(4) C# 依赖项属性

  把对象赋值给属性

 一、依赖属性

1.定义依赖属性

一般情况下只是使用,但如果要自定义WPF控件或者给现有的WPF控件增加新功能时就需要自定义。

定义时需要用到特殊的语法:

  • 静态的
  • 使用readonly只能在构造时初始化
  • 必须是DependencyProperty类实例
  • 属性名称后面要带上Property

定义一个Margin依赖项属性的例子

public static readonly DependencyProperty MarginProperty;

 

2.注册依赖属性

(1)创建FrameworkPropertyMetadata对象,指明通过依赖项属性使用什么服务(支持数据绑定,动画,日志等)

FrameworkPropertyMetadata metadata = new FrameworkPropertyMetadata(new Thickness(), FrameworkPropertyMetadataOptions.AffectsMeasure);

 

(2)调用DependencyProperty.Register()静态方法注册属性 

五个参数

  • 属性名
  • 属性使用的数据类型
  • 拥有该属性的类型
  • 具有附加属性设置的FrameworkPropertyMetadata对象(此参数可选)
  • 用于验证属性的回调函数(此参数可选)

在构造函数中

MarginProperty = DependencyProperty.Register("Margin", typeof(Thickness), typeof(FrameworkElement), metadata, new ValidateValueCallback(FrameworkElement.IsMarginValid));

 

3.封装WPF依赖属性

使用DependencyObject类的SetValue()和GetValue()方法

        public Thickness Margin
        {
            set { SetValue(MarginProperty, value); }
            get { return (Thickness)GetValue(MarginProperty); }
        }

设置属性

element.Margin = new Thickness(5);

 

4.例子

一个按钮继承关系 Button--》ButtonBase--》ContentControl--》Control--》FrameworkElement--》UIElement--》Visual--》DependencyObject--》DispatcherObject--》Object

其中

  • ButtonBase 表示所有 Button 控件的基类,在System.Windows.Controls.Primitives命名空间下(和winfrom下的ButtonBase虽然名字相同,但完全是两条不同的路线)
  • ContentControl  表示包含一段任意类型内容的控件
  • Control 表示用户界面 (UI) 元素的基类,这些元素使用 ControlTemplate 来定义其外观
  • FrameworkElement 提供 WPF元素的属性、事件和方法的 WPF 框架级别集
  • UIElement 是 WPF 核心级实现的基类,这些实现是在 WPF元素和基本表示特性上生成的
  • Visual 为 WPF 中的呈现提供支持,其中包括命中测试、坐标转换和边界框计算
  • DependencyObject 表示参与依赖属性系统的对象,如果设置依赖属性直接继承此类即可

 

完整代码:自定义FrameworkElement类

    class FrameworkElement:UIElement
    {
        public static readonly DependencyProperty MarginProperty;
        
        static FrameworkElement()
        {
            FrameworkPropertyMetadata metadata = new FrameworkPropertyMetadata(new Thickness(), FrameworkPropertyMetadataOptions.AffectsMeasure);
            MarginProperty = DependencyProperty.Register("Margin", typeof(Thickness), typeof(FrameworkElement), metadata, new ValidateValueCallback(FrameworkElement.IsMarginValid));
        }

        private static bool IsMarginValid(object value)
        {
            throw new NotImplementedException();
        }

        public Thickness Margin
        {
            set { SetValue(MarginProperty, value); }
            get { return (Thickness)GetValue(MarginProperty); }
        }
    }

去掉ValidateValueCallback参数

使用

            FrameworkElement element = new FrameworkElement();
            element.Margin = new Thickness(5);

 

4.依赖属性变更通知

有两种方式通知依赖属性变化 --后补

(1)属性值创建绑定

(2)编写能够自动改变其他属性或开始动画的触发器

 

5.共享依赖属性

查看TextBlock源码,没有用DependencyProperty.Register注册,而是使用了TextElement的FontFamilyProperty的依赖属性

FontFamilyProperty = TextElement.FontFamilyProperty.AddOwner(typeof(TextBlock));

 

6.附加依赖属性

附加属性被应用的类不是定义附加属性的那个类,

比如  DockPanel 的DockProperty属性

[CommonDependencyProperty]
public static readonly DependencyProperty DockProperty;
      
static DockPanel()
{
  DockProperty = DependencyProperty.RegisterAttached("Dock", typeof(Dock), typeof(DockPanel), new FrameworkPropertyMetadata(Dock.Left, OnDockChanged), IsValidDock);       
}

DockPanel.Dock 属性作用到了Border上

    <DockPanel LastChildFill="True">
        <Border Height="25" Background="SkyBlue" BorderBrush="Black" BorderThickness="1" DockPanel.Dock="Top">
            <TextBlock Foreground="Black">Dock = "Top"</TextBlock>
        </Border>
        <Border Height="25" Background="SkyBlue" BorderBrush="Black" BorderThickness="1" DockPanel.Dock="Top">
            <TextBlock Foreground="Black">Dock = "Top"</TextBlock>
        </Border>
        <Border Height="25" Background="LemonChiffon" BorderBrush="Black" BorderThickness="1" DockPanel.Dock="Bottom">
            <TextBlock Foreground="Black">Dock = "Bottom"</TextBlock>
        </Border>
        <Border Width="200" Background="PaleGreen" BorderBrush="Black" BorderThickness="1" DockPanel.Dock="Left">
            <TextBlock Foreground="Black">Dock = "Left"</TextBlock>
        </Border>
        <Border Background="White" BorderBrush="Black" BorderThickness="1">
            <TextBlock Foreground="Black">This content will "Fill" the remaining space</TextBlock>
        </Border>
    </DockPanel>

 

 附加属性不需要进行属性封装,可以用于任何依赖对象

 

 

二、属性验证

1.验证回调

 

2.强制回调

 

posted @ 2019-08-22 20:34  富坚老贼  阅读(3154)  评论(0编辑  收藏  举报