WPF依赖项属性、共享依赖项属性、附加属性

1 篇文章 0 订阅

导语

今天用到WPF依赖项属性,距上次看已经过来很长时间,故今天复习下做个笔记,同时希望能帮助到要学习WPF依赖项属性的陪朋友。

依赖项属性

依赖项属性是WPF架构中用C#在标准C#基础属性上做的封装。依赖项属性是WPF样式、动画、数据绑定等的基础,可以说如果没有依赖项属性就没有WPF的样式、动画、数据绑定等灵活的应用。

依赖项属性必须在继承DependencyObject的类中声名。好在大部分WPF控件类都已经继承了DependencyObject类,因为基础类Visual继承了DependencyObject 源代码如下

namespace System.Windows.Media
{
  /// <summary>提供的呈现支持 WPF, ,其中包括命中测试、 坐标转换和边界框计算。</summary>
  public abstract class Visual : DependencyObject, DUCE.IResource
  {
    internal static readonly UncommonField<BitmapEffectState> BitmapEffectStateField = new UncommonField<BitmapEffectState>();
    private static readonly UncommonField<Dictionary<ICyclicBrush, int>> CyclicBrushToChannelsMapField = new UncommonField<Dictionary<ICyclicBrush, int>>();

好了,废话不多说,看看怎么写自己的依赖项属性吧。

1.声明依赖项属性

依赖项属性必须是Public 的静态属性。

public static readonly DependencyProperty TestProperty;

2.注册依赖项属性

DependencyProperty 类没有提供public构造函数,所以我们只能用DependencyProperty 的静态方法去注册依赖项属性。

注意:必须在使用依赖项属性之前注册依赖项属性,所以依赖项属性总是在所在类静态构造函数或者静态字段中注册。

        static DependentClass()
        {
            //依赖项属性 :因为DependencyProperty无public构造函数、只能用静态方法注册。
            //依赖项属性必须在使用之前注册,所以最好写在静态构造函数中,也可以直接写在静态字段中,
            //总之要保证使用前要注册

            FrameworkPropertyMetadata meta = new FrameworkPropertyMetadata();
            meta.DefaultValue = 100;
            meta.CoerceValueCallback = new CoerceValueCallback(TestPropertyCoerceValueCallback);
            meta.PropertyChangedCallback = new PropertyChangedCallback(TestPropertyProertyChangedCallback);

            TestProperty = DependencyProperty.Register("Test", typeof(int), typeof(DependentClass),
                meta, new ValidateValueCallback(TestPropertyValidateValueCallback));

        }

DependencyProperty.Register()方法的参数分别为:依赖项属性名、依赖项属性数据类型、依赖项属性所在类类型、依赖项属性元数据和依赖项属性数据有效性验证回调函数。

其中回调函数行形式为

   private static bool TestPropertyValidateValueCallback(object value)
        {
            //最先执行
            return true;
        }

这个回调函数最先执行,依赖项属性注册时执行,依赖项属性数据改变时执行。在这个函数中只提供属性值,并不提供依赖项属性,所以没法做一些验证,在这里主要验证依赖项属性的值的类型和格式是否有效,有效返回ture,无效返回false。

依赖项属性元数据这个对象属性有限,可以自己看看智能提示说明,都很好理解。这里主要说一下它的两个回调函数。

 private static object TestPropertyCoerceValueCallback(DependencyObject sender, object value)
        {
            //这个回调函数必须返回object,之后执行
            return value;
        }

这个函数在ValidateValueCallback之后执行,在这里可以对依赖项属性值做详细验证(如依赖项属性包含的最大、最小值、newValue  oldValue等)

最后是

        public static void TestPropertyProertyChangedCallback(DependencyObject d,
            DependencyPropertyChangedEventArgs e)
        {
            //最后执行
        }

这个回调是属性值已经发生改变时执行。因为依赖项属性值的改变可以不通过包装器(就是咱们熟悉的get{} set{}属性,接下来说明)而通过其他(如数据绑定、动画等),所以依赖项属性值变化要触发的一些动作可以写在这里。

3.包装依赖项属性

依赖项属性也是一种属性,所以要包装一下,暴露出一般属性的特性方便使用

        public int Test
        {
            get { return (int)GetValue(TestProperty); }
            set
            {
                SetValue(TestProperty, value);
            }
        }

这样依赖项属性就OK拉。

共享依赖项属性

如果依赖类要添加的依赖项属性和既有类中依赖项属性完全相同,可直接用既有类依赖项属性,只需要在静态构造函数中注册一下就可以

 class TestProperty1 : UIElement
    {
        //测试共享依赖属性
        public int Test
        {
            set
            {
                SetValue(TestProperty, value);
            }
            get
            {
                return (int)GetValue(TestProperty) ;
            }
        }

        public static readonly DependencyProperty TestProperty;

        static TestProperty1()
        {
            TestProperty = DependentClass.TestProperty.AddOwner(typeof(TestProperty1));
        }

    }

附加属性

附加属性是一种特殊的依赖项属性。关于附加属性的说明很多,我简单明了的总结就是:被用到在注册类外的其他类中的依赖项属性。比如Grid.row  Gird.column 几乎可以用在任何类中。附加属性是一种依赖属性,只有在注册时调用RegisterAttached方法。包装器稍微不一样,看如下代码

    static AttachClass()
        {
            //依赖项属性 :因为DependencyProperty无public构造函数、只能用静态方法注册。
            //依赖项属性必须在使用之前注册,所以最好写在静态构造函数中,也可以直接写在静态字段中,
            //总之要保证使用前要注册

            FrameworkPropertyMetadata meta = new FrameworkPropertyMetadata();
            meta.DefaultValue = 100;
            meta.CoerceValueCallback = new CoerceValueCallback(TestPropertyCoerceValueCallback);
            meta.PropertyChangedCallback = new PropertyChangedCallback(TestPropertyProertyChangedCallback);

            TestProperty = DependencyProperty.RegisterAttached("Test", typeof(int), typeof(AttachClass),
                meta, new ValidateValueCallback(TestPropertyValidateValueCallback));

        }

        private static bool TestPropertyValidateValueCallback(object value)
        {
            //最先执行
            return true;
        }

        public static void TestPropertyProertyChangedCallback(DependencyObject d,
            DependencyPropertyChangedEventArgs e)
        {
            //最后执行
        }

        private static object TestPropertyCoerceValueCallback(DependencyObject sender, object value)
        {
            //这个回调函数必须返回object,之后执行
            return value;
        }
    }

 

好了,就写这么多吧。

附测试程序代码

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;

namespace TestDependencyProperty
{
    class DependentClass:UIElement
    {
        public static readonly DependencyProperty TestProperty;

        public int Test
        {
            get { return (int)GetValue(TestProperty); }
            set
            {
                SetValue(TestProperty, value);
            }
        }

        static DependentClass()
        {
            //依赖项属性 :因为DependencyProperty无public构造函数、只能用静态方法注册。
            //依赖项属性必须在使用之前注册,所以最好写在静态构造函数中,也可以直接写在静态字段中,
            //总之要保证使用前要注册

            FrameworkPropertyMetadata meta = new FrameworkPropertyMetadata();
            meta.DefaultValue = 100;
            meta.CoerceValueCallback = new CoerceValueCallback(TestPropertyCoerceValueCallback);
            meta.PropertyChangedCallback = new PropertyChangedCallback(TestPropertyProertyChangedCallback);

            TestProperty = DependencyProperty.Register("Test", typeof(int), typeof(DependentClass),
                meta, new ValidateValueCallback(TestPropertyValidateValueCallback));

        }

        private static bool TestPropertyValidateValueCallback(object value)
        {
            //最先执行
            return true;
        }

        public static void TestPropertyProertyChangedCallback(DependencyObject d,
            DependencyPropertyChangedEventArgs e)
        {
            //最后执行
        }

        private static object TestPropertyCoerceValueCallback(DependencyObject sender, object value)
        {
            //这个回调函数必须返回object,之后执行
            return value;
        }
    }

    class TestProperty1 : UIElement
    {
        //测试共享依赖属性
        public int Test
        {
            set
            {
                SetValue(TestProperty, value);
            }
            get
            {
                return (int)GetValue(TestProperty) ;
            }
        }

        public static readonly DependencyProperty TestProperty;

        static TestProperty1()
        {
            TestProperty = DependentClass.TestProperty.AddOwner(typeof(TestProperty1));
        }

    }

    //附件属性 ,注意自己需要记住区别:附加属性不被用到定义属性的类,而是用到其他的类
    class AttachClass : UIElement
    {
        public static readonly DependencyProperty TestProperty;

        public static void SetTest(UIElement element, int value)
        {
            element.SetValue(TestProperty, value);
        }

        public static int GetTest(UIElement element)
        {
            return (int)element.GetValue(TestProperty);
        }


        public  int Test
        {
            get { return (int)GetValue(TestProperty); }
            set
            {
                SetValue(TestProperty, value);
            }
        }
        static AttachClass()
        {
            //依赖项属性 :因为DependencyProperty无public构造函数、只能用静态方法注册。
            //依赖项属性必须在使用之前注册,所以最好写在静态构造函数中,也可以直接写在静态字段中,
            //总之要保证使用前要注册

            FrameworkPropertyMetadata meta = new FrameworkPropertyMetadata();
            meta.DefaultValue = 100;
            meta.CoerceValueCallback = new CoerceValueCallback(TestPropertyCoerceValueCallback);
            meta.PropertyChangedCallback = new PropertyChangedCallback(TestPropertyProertyChangedCallback);

            TestProperty = DependencyProperty.RegisterAttached("Test", typeof(int), typeof(AttachClass),
                meta, new ValidateValueCallback(TestPropertyValidateValueCallback));

        }

        private static bool TestPropertyValidateValueCallback(object value)
        {
            //最先执行
            return true;
        }

        public static void TestPropertyProertyChangedCallback(DependencyObject d,
            DependencyPropertyChangedEventArgs e)
        {
            //最后执行
        }

        private static object TestPropertyCoerceValueCallback(DependencyObject sender, object value)
        {
            //这个回调函数必须返回object,之后执行
            return value;
        }
    }



}
<Window x:Class="TestDependencyProperty.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:loacl ="clr-namespace:TestDependencyProperty"
        Title="MainWindow" Height="350" Width="525" Loaded="Window_Loaded">
    <Grid >
        <StackPanel Background="Green" loacl:AttachClass.Test="20">
            <loacl:MyClass Click="mc_Click" x:Name="mc" 
                           MyTest="{Binding Path=Value}" Content="{Binding ElementName=test2, Path=Test}"></loacl:MyClass>
            <loacl:DependentClass x:Name="test1" Test="20"></loacl:DependentClass>
            <loacl:TestProperty1 x:Name="test2" Test ="30"></loacl:TestProperty1>
        </StackPanel>
        
    </Grid>
</Window>



上一篇:

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值