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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容