WPF 依赖属性

依赖属性的定义

1、定义依赖属性
意义:支持WPF的特性功能:动画、数据绑定、样式。

2、步骤:

  • 声明:static,readonly,名称以Property结尾;
  • 注册:DependencyProperty.Register;
  • 包装:GetValue()| SetValue() ——由DependencyObject对象提供;

依赖属性所在的类需继承于DependencyObject
在这里插入图片描述

        public string NewPassword
        {
            get { return (string)GetValue(NewPasswordProperty); }
            set { SetValue(NewPasswordProperty, value); }
        }
        public static readonly DependencyProperty NewPasswordProperty =
            DependencyProperty.Register("NewPassword", typeof(string), typeof(MainWindow), new PropertyMetadata(default(string)));

PropertyMetadata用来定义属性的元数据(默认数据)。

FrameworkPropertyMetadata

FrameworkPropertyMetadata继承于PropertyMetadata
WPF 依赖属性_第1张图片

参数FrameworkPropertyMetadataOptions:

WPF 依赖属性_第2张图片
枚举类型,选项详解如下:

  • AffectsArrange、AffectsMeasure、AffectsParentArrange、AffectsParentMeasure:属性变化的时候,需要通知容器进行重新测量和排列。Margin值变化的时候,就会把相邻的对象挤开
  • AffectsRender:属性值的变化导致元素重新渲染、重新绘制
  • BindsTwoWayByDefault:默认情况以双向绑定的方式处理绑定行为
  • Inherits:继承。FontSize,父对象进行这个属性设置的时候,会对子对象进行相同的影响
  • IsAnimationProhibited:这个属性不能用于动画
  • IsNotDataBindable:不能使用表达式,设置依赖属性
  • Journal:Page开发,属性的值会被保存到 =日志
  • SubPropertiesDoNotAffectRender:对象属性子属性变化时,不去重新渲染对象
参数PropertyChangedCallback

属性变化通知回调

参数CoerceValueCallback

强制回调,强制转换值

ValidateValueCallback

表示用作验证依赖属性有效值的回调的方法

        public int MyProperty
        {
            get { return (int)GetValue(MyPropertyProperty); }
            set
            {
                SetValue(MyPropertyProperty, value);
            }
        }

        static FrameworkPropertyMetadata metadata = new FrameworkPropertyMetadata(
            default(int),
            new PropertyChangedCallback(OnPropertyChanged),
            new CoerceValueCallback(OnCoreceValue));

        public static readonly DependencyProperty MyPropertyProperty =
            DependencyProperty.Register(
                "MyProperty",
                typeof(int),
                typeof(MainWindow),
                metadata,
                new ValidateValueCallback(OnValidateValue));
 
        private static bool OnValidateValue(object value)
        {
            if ((int)value > 1500)
                return false;
            return true;
        }
        private static object OnCoreceValue(DependencyObject d, object value)
        {
            var min = (d as MainWindow).Min;
            var max = (d as MainWindow).Max;
            if ((int)value < min)
                return min;
            if ((int)value > max)
                return max;
            return value;
        }
        private static void OnPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            Console.WriteLine("值变化了[OnPropertyChanged]:" + e.NewValue);
        }

依赖属性的继承

1、Inherits标记
2、AddOwner方法
通过该种写法可以实现依赖属性值得共享。

    public class Control1 : ContentControl
    {
        public int Prop
        {
            get { return (int)GetValue(PropProperty); }
            set { SetValue(PropProperty, value); }
        }
        public static readonly DependencyProperty PropProperty =
            DependencyProperty.Register("Prop", typeof(int), typeof(Control1),
                 new FrameworkPropertyMetadata(default(int), FrameworkPropertyMetadataOptions.Inherits));

    }
    public class Control2 : ContentControl
    {
        public int Prop
        {
            get { return (int)GetValue(PropProperty); }
            set { SetValue(PropProperty, value); }
        }
        public static readonly DependencyProperty PropProperty =
            Control1.PropProperty.AddOwner(typeof(Control2),
                new FrameworkPropertyMetadata(default(int), FrameworkPropertyMetadataOptions.Inherits));

    }
<local:Control1 Prop="123">
    <local:Control2 x:Name="c2"/>
local:Control1>
<local:Control2 Prop="456">
    <local:Control1 x:Name="c1"/>
local:Control2>

Control1和Control2的共享了属性Prop值。

附加依赖属性

1、使用场景
有一些属性不是依赖,没有可以绑定的功能
PasswordBox->Password
2、定义
DependencyProperty.RegisterAttached、Get包装方法、Set包装方法

    public class PasswordAttached
    {
        public static readonly DependencyProperty PasswordProperty =
                DependencyProperty.RegisterAttached(
                      "Password",
                      typeof(string),
                      typeof(PasswordAttached),
                      new FrameworkPropertyMetadata("", new PropertyChangedCallback(OnPropertyChanged)));

        public static string GetPassword(DependencyObject d)
        {
            return (string)d.GetValue(PasswordProperty);
        }
        public static void SetPassword(DependencyObject d, string value)
        {
            d.SetValue(PasswordProperty, value);
        }

        public static readonly DependencyProperty AttachProperty =
                DependencyProperty.RegisterAttached(
                      "Attach",
                      typeof(bool),
                      typeof(PasswordAttached),
                      new FrameworkPropertyMetadata(default(bool), new PropertyChangedCallback(OnAttachChanged)));

        public static bool GetAttach(DependencyObject d)
        {
            return (bool)d.GetValue(PasswordProperty);
        }
        public static void SetAttach(DependencyObject d, bool value)
        {
            d.SetValue(PasswordProperty, value);
        }

        static bool _isUpdating = false;
        private static void OnPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            PasswordBox pb = d as PasswordBox;
            if (pb == null || e.NewValue == null) return;

            if (!_isUpdating)
            {
                pb.PasswordChanged -= Pb_PasswordChanged;
                pb.Password = e.NewValue.ToString();
                pb.PasswordChanged += Pb_PasswordChanged;
            }
        }

        private static void OnAttachChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            PasswordBox pb = d as PasswordBox;
            if (pb == null) return;

            pb.PasswordChanged += Pb_PasswordChanged;
        }

        private static void Pb_PasswordChanged(object sender, RoutedEventArgs e)
        {
            PasswordBox pb = sender as PasswordBox;

            _isUpdating = true;
            SetPassword(pb, pb.Password);
            _isUpdating = false;
        }
    }
    public partial class MainWindow : Window
    {
        public string NewPassword
        {
            get { return (string)GetValue(NewPasswordProperty); }
            set { SetValue(NewPasswordProperty, value); }
        }
        public static readonly DependencyProperty NewPasswordProperty =
            DependencyProperty.Register("NewPassword", typeof(string), typeof(MainWindow), new PropertyMetadata(default(string)));

        public MainWindow()
        {
            InitializeComponent();
        }

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            this.NewPassword = "123";
        }
    }
	<PasswordBox Height="30" Password="" 
                         local:PasswordAttached.Attach="true"
                         local:PasswordAttached.Password="{Binding NewPassword,RelativeSource={RelativeSource AncestorType=Window,Mode=FindAncestor},Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"/>
	<Button Content="Button" Click="Button_Click" Height="40"/>

local:PasswordAttached.Password绑定了NewPassword,可实现属性值变化通知到界面,依赖属性的底层实现了通知功能。

类型转换器

通过类型转换器,可以在xaml中将字符串(例如:“1,5”)赋值为依赖属性Rangle对象。

        public Range Range
        {
            get { return (Range)GetValue(RangeProperty); }
            set { SetValue(RangeProperty, value); }
        }
        public static readonly DependencyProperty RangeProperty =
            DependencyProperty.Register("Range", typeof(Range), typeof(MainWindow), new PropertyMetadata(default(Range)));
    public class RangeTypeConverter : TypeConverter
    {
        public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
        {
            if (sourceType == typeof(string))
                return true;
            return base.CanConvertFrom(context, sourceType);
        }
        public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
        {
            string[] valueArray = value.ToString().Split(',');
            if (valueArray.Length == 2)
                return new Range(int.Parse(valueArray[0]), int.Parse(valueArray[1]));
            return base.ConvertFrom(context, culture, value);
        }
        public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
        {
            return base.CanConvertTo(context, destinationType);
        }
        public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType)
        {
            return (value as Range).ToString();
            //return base.ConvertTo(context, culture, value, destinationType);
        }
    }
    [TypeConverter(typeof(RangeTypeConverter))]
    public class Range
    {
        public int MinValue { get; set; }
        public int MaxValue { get; set; }

        public Range() { }
        public Range(int min, int max)
        {
            this.MinValue = min;
            this.MaxValue = max;
        }

        public override string ToString()
        {
            return $"{MinValue},{MaxValue}";
        }
    }

你可能感兴趣的:(WPF,wpf,c#)