(原创)2. WPF中的依赖属性之二
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,在鼠标移动到按钮上的时候,设置动画,如下代码 (编辑:安卓应用网) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |
