WPF之依赖属性

本文章切绍以下内容
1.WPF依赖属性
2.WPF附加依赖属性
3.WPF依赖属性的相关回调

C#语言类成员变量分为属性、字段

-字段 如下
public int Age;
-属性 如下

private int _Age;
public int Age{
  get{ return _Age;}
  set{ _Age = value;}
}

WPF依赖属性

依赖属性相关概念可以参数 [依赖属性](依赖属性概述 - WPF .NET | Microsoft Learn
)

依赖属性和普通属性差别

依赖属性和普通属性一个重要的差别就是:依赖属性可以进行绑定,
比如
PasswordBox中的Password由于是是一个普通属性,所以它无法进行绑定{Binding...}
TextBlock中的Text是一个依赖属性,所以它可以进行绑定{Binding....}

如何定义依赖属性

注册依赖属性有三个方法如下

public static DependencyProperty Register(string name, Type propertyType, Type ownerType);
public static DependencyProperty Register(string name, Type propertyType, Type ownerType, PropertyMetadata typeMetadata);
public static DependencyProperty Register(string name, Type propertyType, Type ownerType, PropertyMetadata typeMetadata, ValidateValueCallback validateValueCallback);

第二个函数,指定依赖属性的默认值,
第三个函数,指定依赖属性的默认值外还可以定义属性值的合法性验证回调函数。
其中PropertyMetadata的构造函数如下

public PropertyMetadata();
public PropertyMetadata(object defaultValue);
public PropertyMetadata(PropertyChangedCallback propertyChangedCallback);
public PropertyMetadata(object defaultValue, PropertyChangedCallback propertyChangedCallback);
public PropertyMetadata(object defaultValue, PropertyChangedCallback propertyChangedCallback, CoerceValueCallback coerceValueCallback);

第二个函数,指定依赖属性的默认值
第三个函数,指定依赖属性变化时的回调函数
第四个函数,指定依赖属性的默认值和依赖属性变化时的回调函数
第五个函数,指定依赖属性的默认值和依赖属性变化时的回调函数和依赖属性值变化时候可以修正值的回调函数。
我们通过自定义一个用户控件(DepdencyPropControl),该控件中自定义一个普通属性NorValue和依赖属性来演示普通属性和依赖属性DepValue的差异。

private string _NorValue;
public string NorValue
{
    get
    {
        return _NorValue;
    }
    set
    {
        NorValue = value;
    }
}
public string DepValue
{
    get { return (string)GetValue(DepValueProperty); }
    set { SetValue(DepValueProperty, value); }
}
// Using a DependencyProperty as the backing store for DepValue.  This enables animation, styling, binding, etc...
public static readonly DependencyProperty DepValueProperty =
            DependencyProperty.Register("DepValue", typeof(string), typeof(DepdencyPropControl), new PropertyMetadata("我是默认值"));

DepdencyPropControl.xaml内容如下

<Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="Auto"/>
            <ColumnDefinition/>
        </Grid.ColumnDefinitions>
        <TextBlock Grid.Row="0" Grid.Column="0" Text="依赖属性DepValue:"/>
        <TextBox Grid.Row="0" Grid.Column="1" Text="{Binding DepValue, RelativeSource={RelativeSource AncestorType=local:DepdencyPropControl}}"/>
        <TextBlock Grid.Row="1" Grid.Column="0" Text="普通属性NorValue:"/>
        <TextBox Grid.Row="1" Grid.Column="1" Text="{Binding NorValue, RelativeSource={RelativeSource AncestorType=local:DepdencyPropControl}}"/>
</Grid>

在Window.xaml中使用该控件如下,可以看到对于普通属性NorValue无法进行绑定提示如下错误


无法绑定普通属性错误.png

普通属性和依赖属性使用如下

<GroupBox Header="依赖属性和普通属性" Margin="5">
                <StackPanel>
                    <local:DepdencyPropControl/>
                    <TextBox Margin="5" x:Name="InputName"/>
                    <local:DepdencyPropControl
                        DepValue="{Binding Text,ElementName=InputName}"
                        NorValue="adfadsf"/>
                </StackPanel>
</GroupBox>

显示结果如下


依赖属性结果.png

WPF附加依赖属性

依赖属性是附加在某个控件中的属性,而附加依赖属性则不属于某个控件,但是可以把该附加依赖属性加到某个控件上,这样这个控件就拥有了该附加属性。
我们还是用刚才定义的控件DepdencyPropControl来演示。

定义附加依赖属性

输入propa 然后再两下tab键可以自动生成附加依赖属性定义
新建一个类AttachDepProp内容如下

class AttachDepProp
    {
        public static string GetAttachTitle(DependencyObject obj)
        {
            return (string)obj.GetValue(AttachTitleProperty);
        }

        public static void SetAttachTitle(DependencyObject obj, string value)
        {
            obj.SetValue(AttachTitleProperty, value);
        }

        // Using a DependencyProperty as the backing store for AttachTitle.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty AttachTitleProperty =
            DependencyProperty.RegisterAttached("AttachTitle", typeof(string), typeof(AttachDepProp), new PropertyMetadata("我是附加依赖属性默认值"));
    }

自定义控件AttachPropControl使用该附加依赖属性,如下

<Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="Auto"/>
            <ColumnDefinition/>
        </Grid.ColumnDefinitions>
        <TextBlock Grid.Column="0" Text="附加依赖属性:"/>
        <TextBlock Grid.Column="1" Text="{Binding Path=(local:AttachDepProp.AttachTitle),RelativeSource={RelativeSource AncestorType=local:AttachPropControl}}"/>
    </Grid>

在Window.xaml中使用附加依赖属性如下

<GroupBox Header="附加依赖属性" Margin="5">
                <StackPanel Orientation="Vertical">
                    <local:AttachPropControl Margin="5"/>
                    <TextBox x:Name="InputAttachName"/>
                    <local:AttachPropControl local:AttachDepProp.AttachTitle="{Binding Text, ElementName=InputAttachName}"/>
                </StackPanel>
</GroupBox>

结果如下


附加依赖属性结果.png

WPF依赖属性的相关回调

我们还是用之前定义的控件DepdencyPropControl来演示

1、PropertyChangedCallback和CoerceValueCallback

PropertyChangedCallback是在依赖属性值发生变化的时候才会调用
CoerceValueCallback这个回调比如依赖属性非法时候,给用户一个机会修改依赖属性值,这两个回调同时演示。
自定义一个用户控件CoerceControl,并且添加一个依赖属性如下

public string MyCoerceValue
        {
            get { return (string)GetValue(MyCoerceValueProperty); }
            set { SetValue(MyCoerceValueProperty, value); }
        }

        // Using a DependencyProperty as the backing store for CoerceValue.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty MyCoerceValueProperty =
            DependencyProperty.Register("MyCoerceValue", typeof(string), typeof(CoerceControl), new PropertyMetadata("11", PropertyValChangedCallback, MyCoerceValueCallback));

        private static void PropertyValChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            Console.WriteLine("value changed callback:");
        }

        private static object MyCoerceValueCallback(DependencyObject d, object baseValue)
        {
            Console.WriteLine("MyCoerceValue callback :");
            string val = baseValue as string;
            if(string.IsNullOrEmpty(val) || val.Length > 6)
            {
                return "Hello World";
            }
            return baseValue;
        }

这个表示依赖属性MyCoerceValue的值为空或者输入长度大于是6的时候,该依赖属性返回值Hello World。
CoerceControl.xaml如下

<Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="Auto"/>
            <ColumnDefinition/>
        </Grid.ColumnDefinitions>
        <TextBlock Grid.Column="0" Text="验证CoerceValueCallback:"/>
        <TextBlock Grid.Column="1" Text="{Binding MyCoerceValue,RelativeSource={RelativeSource AncestorType=local:CoerceControl}}"/>
</Grid>

Windowm.xaml中使用CoerceControl

<GroupBox Header="验证数据合法回调" Margin="5">
  <StackPanel Orientation="Vertical">
    <TextBox x:Name="InputCoerceValueName" Margin="5"/>
    <local:CoerceControl MyCoerceValue="{Binding Text,ElementName=InputCoerceValueName}"/>
  </StackPanel>
</GroupBox>

2、ValidateValueCallback

我们自定义一个用户控件ValidateControl,并且定义一个依赖属性ValidateValue,默认值为11,附加验证回调,该属性只接收输入数字0-100不在这范围表示数据非法,如下

public string ValidateValue
        {
            get { return (string)GetValue(ValidateValueProperty); }
            set { SetValue(ValidateValueProperty, value); }
        }
        // Using a DependencyProperty as the backing store for ValidateValue.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty ValidateValueProperty =
            DependencyProperty.Register("ValidateValue", typeof(string), typeof(DepdencyPropControl), new PropertyMetadata("11"), ValueValidateCallback);
        private static bool ValueValidateCallback(object value)
        {
            string val = value as string;
            if (string.IsNullOrEmpty(val))
            {
                Console.WriteLine("合法...");
                return true;
            }
            try
            {
                int num = int.Parse(val);
                if (num >= 0 && num <= 100)
                {
                    Console.WriteLine("合法...");
                    return true;
                }
            }
            catch(Exception e)
            {

            }

            Console.WriteLine("非法...");;
            return false;
        }

在Window.xaml中使用如下:

<GroupBox Header="验证数据合法回调" Margin="5">
  <StackPanel Orientation="Vertical">
    <TextBox x:Name="InputValidateValueName" Margin="5"/>
    <local:ValidateControl ValidateValue="{Binding Text,ElementName=InputValidateValueName}"/>
  </StackPanel>
</GroupBox>

验证过程:
在名为InputValidateValueName的TextBox中输入0-100的字符,会在DepdencyPropControl控件中显示,
如果输入的非0-100字符,DepdencyPropControl控件会显示ValidateValue的默认值11

本文Demo-DependencyPropWindow

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,723评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,003评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,512评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,825评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,874评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,841评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,812评论 3 416
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,582评论 0 271
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,033评论 1 308
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,309评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,450评论 1 345
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,158评论 5 341
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,789评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,409评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,609评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,440评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,357评论 2 352

推荐阅读更多精彩内容