加入收藏 | 设为首页 | 会员中心 | 我要投稿 安卓应用网 (https://www.0791zz.com/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 综合聚焦 > 程序设计 > 正文

(原创)2. WPF中的依赖属性之二

发布时间:2020-05-22 15:10:03 所属栏目:程序设计 来源:互联网
导读:1 依赖属性 1.1 官方依赖属性最终值选取过程 WPF属性系统对依赖属性操作的基本步骤如下: 第一,确定Base Value,对同一个属性的赋值可能发生在很多地方。还用Button的宽度来进行举例,可能在Style或者Trigger中对其进行赋值,也可能在xaml中进行赋值(等同与

1 依赖属性

1.1 官方依赖属性最终值选取过程

WPF属性系统对依赖属性操作的基本步骤如下:

第一,确定Base Value,对同一个属性的赋值可能发生在很多地方。还用Button的宽度来进行举例,可能在Style或者Trigger中对其进行赋值,也可能在xaml中进行赋值(等同与在代码中赋值),这个Base Value就要确定这些值中优先级最高的值,把它作为Base Value;

    <Window.Resources>
        <Style TargetType="Button">
            <Setter Property="Width" Value="100"/>
            <Setter Property="Height" Value="30"/>
            <Style.Triggers>
                <Trigger Property="IsPressed" Value="False">
                    <Setter Property="Width" Value="3000"/>
                </Trigger>
            </Style.Triggers>
        </Style>
        <loc:WidthConvertr x:Key="WidthConverter"/>
    </Window.Resources>
    <Grid>
        <Button Name="ButtonTest" 
                            FontSize="13"  
                            Background="Blue"  
                            >ButtonSubSub</Button>
    </Grid>

在代码中查看ValueSource截图为图1


看到BaseValueSource是StyleTrigger类型的,BaseValue在选取的规则中,都应当按照如下的优先级别进行选取,从上到下是依次增大的,可以看到StyleTrigger比Style要高,这和上边的xaml中示例中的相同,如果把Trigger去掉,那么BaseValueSource是Style了。如果xaml中什么都没有设定,在代码中也没有赋值,那么,BaseValueSource就会是Default类型;

  public enum BaseValueSource   {     Unknown = 0,Default = 1,Inherited = 2,DefaultStyle = 3,DefaultStyleTrigger = 4,Style = 5,TemplateTrigger = 6,StyleTrigger = 7,ImplicitStyleReference = 8,ParentTemplate = 9,ParentTemplateTrigger = 10,Local = 11,}

第二,获取绑定源中的值。这个步骤容易产生理解上的混乱,如果在第一步中,设置了LocalValue,即1.1中阐述的Binding或者在xaml中赋值,并且如果是Binding的话,就会经过第二步的计算,将其转化成一个实际的值;如果不是,就直接判断以下的情况;

第三,获取动画值。如果当前属性正在作动画,那么因动画而产生的值会优于前面获得的值,这个也就是WPF中常说的动画优先;

第四,对最终值进行强制值约定。利用在FrameworkPropertyMetadata中传入了CoerceValueCallback,进行数据的逻辑限制,例如边界限制,特殊值限制等。

第五,对最终值进行最后验证。利用在Register的时候传入了ValidateValueCallback;

参考http://www.cnblogs.com/Zhouyongh/archive/2009/10/20/1586278.html

1.2 LocalValue中的直接赋值和BindingExpress

依赖属性中的LocalValue,只能设置通过在xaml中赋值或者直接在代码中进行赋值或者通过Binding对赋值行绑定,但三种方式不能同时在依赖属性中进行存在,也就是说,这三种给依赖属性提供值的方式,在运行时,最后调用者覆盖之前为LocalValue的赋值,并且发生作用。

例如:先编写一个宽度的数据源

    public class WidhtHeightBindingedClass : INotifyPropertyChanged
    {
        private double _height;
        public double Height
        {
            get
            {
                return _height;
            }
            set
            {
                _height = value;
                Notify("Height");
            }
        }
        private double _width;
        public double Width
        {
            get
            {
                return _width;
            }

            set
            {
                _width = value;
                Notify("Width");
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;
        private void Notify(string proerptyName)
        {
            var handler = this.PropertyChanged;
            if (handler != null)
            {
                handler(this,new PropertyChangedEventArgs(proerptyName));
            }
        }
    }
我们可以在xaml中,设置Button的宽度,
    <Grid>
        <Button Name="ButtonTest" 
                            FontSize="13"  
                            Background="Blue"  
                            Width="400"
                            >ButtonSubSub</Button>
    </Grid>

但,在Loaded事件处理函数中,有如下代码进行测试

        private void Window_Loaded(object sender,RoutedEventArgs e)
        {
            //@Test 1: valueLocalValue中,BaseValueSource = Local; IsAnnimated = false; IsCoerced = false; IsExpression = false
            //@Test 1: LocalValue = 400
            object valueLocalValue = ButtonTest.ReadLocalValue(FrameworkElement.WidthProperty);//
            ValueSource valueSource = DependencyPropertyHelper.GetValueSource(
                ButtonTest,FrameworkElement.WidthProperty);

            //@Test 2: afterBindingValueSource.BaseValueSource = Local; 
            //                                 IsAnnimated = false; 
            //                                 IsCoerced = false; 
            //                                 IsExpression = true
            //@Test 2: afterBindingLocalValue: BindingExpression 是一个BindingExpression类型,不再是值;
            //                                 其中DataSource= WidhtHeightBindingedClass;
            Binding binding = new Binding("Width");
            binding.Source = this.WidthHeightSource;
            BindingOperations.SetBinding(ButtonTest,WidthProperty,binding);

            object afterBindingLocalValue = ButtonTest.ReadLocalValue(FrameworkElement.WidthProperty);//
            ValueSource afterBindingValueSource = DependencyPropertyHelper.GetValueSource(ButtonTest,FrameworkElement.WidthProperty);


            BindingOperations.ClearBinding(ButtonTest,WidthProperty);
            //@Test 3: afterUnBindingValueSource.BaseValueSource = Default; 
            //                                 IsAnnimated = false; 
            //                                 IsCoerced = false; 
            //                                 IsExpression = false;
            //@Test 3: afterUnBindingLocalValue:DependecyProperty.UnsetValue
            object afterUnBindingLocalValue = ButtonTest.ReadLocalValue(FrameworkElement.WidthProperty);//
            ValueSource afterUnBindingValueSource = DependencyPropertyHelper.GetValueSource(ButtonTest,FrameworkElement.WidthProperty);
        }
    }

如果,从Test1,2,3中,可以看出,在xaml赋值(等同于后台代码直接赋值)和用Binding来绑定值,只能保存一个值。

1.3 Annimate,BaseValue与Coerce,Validate的区别

动画值要比在BaseValue和Binding获取的值具有更高的优先权(注意,实际上Binding值和BaseValue中的LocalValue是具有相同高的优先级,在具体要采用Binding获取的值还是LocalValue,要看运行时,采用最后一次设置的值,具体可以参考1.2中的例子,很明显的证明这点),当处于动画设置状态的时候,属性的最终值就被设定为动画值;和BaseValue和Binding获取的值一样,动画值也要通过Coerce和Validate的验证,最终获得属性的最终值。

有如下的示例,定义MyButton,继承于Button,并且在MyButton中定义依赖属性MyDefinedProperty,定义Trigger,当鼠标在MyButton上的时候,开始动画,可以看到打印出来的信息,每个值都要经过Coerce和Validate的验证。

public partial class MyButton : Button
  {
    public MyButton()
    {
      InitializeComponent();
    }
    public static readonly DependencyProperty MyDefinedProperty = DependencyProperty.Register("MyDefinded",typeof(double),typeof(MyButton),new FrameworkPropertyMetadata(default(double),FrameworkPropertyMetadataOptions.None,new PropertyChangedCallback(OnValueChanged),new CoerceValueCallback(CoerceValue)),new ValidateValueCallback(IsValidateValue)
    );

    private static void OnValueChanged(DependencyObject d,DependencyPropertyChangedEventArgs e)
    {
      Console.WriteLine("{0} OnValueChanged new value is {1}",d.GetType().ToString(),e.NewValue);
    }

    private static object CoerceValue(DependencyObject d,object value)
    {
      Console.WriteLine("{0} CoerceValue value is {1}",value);
      return value;
    }

    private static bool IsValidateValue(object value)
    {
      Console.WriteLine("MyButton ValidateValue value is {1}",value);
      return true;
    }

    public double MyDefinded
    {
      get
      {
        return (double)GetValue(MyDefinedProperty);
      }
      set
      {
        SetValue(MyDefinedProperty,value);
      }
    }
  }

同样,在xaml中定义此类型的Button,并且,定义Trigger,在鼠标移动到按钮上的时候,设置动画,如下代码

(编辑:安卓应用网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读