(原创)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值具有更高的优先权,当前处于动画设置状态的时候,Value值就被设定为动画值;有如下的示例,定义MyButton,其是继承Button,并且在MyButton中定义依赖属性MyDefinedProperty
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}", d.GetType().ToString(), 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,在鼠标移动到按钮上的时候,设置动画,如下代码
<Window x:Class="LocalBaseBindingExpress.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="MainWindow"
Height="350"
Width="525"
xmlns:loc="clr-namespace:LocalBaseBindingExpress"
Loaded="Window_Loaded">
<Window.Resources>
<Style TargetType="loc:MyButton">
<Setter Property="Width" Value="100"/>
<Setter Property="Height" Value="30"/>
<Style.Triggers>
<EventTrigger RoutedEvent="Button.MouseEnter" >
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetProperty="(loc:MyButton.MyDefinded)"
To="1000" Duration="0:1:5"/>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Style.Triggers>
</Style>
<loc:WidthConvertr x:Key="WidthConverter"/>
</Window.Resources>
<Grid>
<loc:MyButton x:Name="ButtonTest"
FontSize="13"
Background="Blue"
Click="ButtonTest_Click" >ButtonSubSub
</loc:MyButton>
</Grid>
</Window>
当我们把鼠标放在按钮上的时候,在调试窗口,可以打印出如下的信息
MyButton ValidateValue value is 65.3535369230769
LocalBaseBindingExpress.MyButton CoerceValue value is 65.3535369230769
LocalBaseBindingExpress.MyButton OnValueChanged new value is 65.3535369230769
MyButton ValidateValue value is 65.3571092307692
LocalBaseBindingExpress.MyButton CoerceValue value is 65.3571092307692
LocalBaseBindingExpress.MyButton OnValueChanged new value is 65.3571092307692
MyButton ValidateValue value is 65.8233815384615
LocalBaseBindingExpress.MyButton CoerceValue value is 65.8233815384615
LocalBaseBindingExpress.MyButton OnValueChanged new value is 65.8233815384615
MyButton ValidateValue value is 66.3182046153846
LocalBaseBindingExpress.MyButton CoerceValue value is 66.3182046153846
LocalBaseBindingExpress.MyButton OnValueChanged new value is 66.3182046153846
MyButton ValidateValue value is 66.8083676923077
LocalBaseBindingExpress.MyButton CoerceValue value is 66.8083676923077
LocalBaseBindingExpress.MyButton OnValueChanged new value is 66.8083676923077
MyButton ValidateValue value is 67.2775246153846
LocalBaseBindingExpress.MyButton CoerceValue value is 67.2775246153846
LocalBaseBindingExpress.MyButton OnValueChanged new value is 67.2775246153846
MyButton ValidateValue value is 67.7459646153846
LocalBaseBindingExpress.MyButton CoerceValue value is 67.7459646153846
LocalBaseBindingExpress.MyButton OnValueChanged new value is 67.7459646153846
MyButton ValidateValue value is 68.2240753846154
LocalBaseBindingExpress.MyButton CoerceValue value is 68.2240753846154
LocalBaseBindingExpress.MyButton OnValueChanged new value is 68.2240753846154
MyButton ValidateValue value is 68.9506415384615
LocalBaseBindingExpress.MyButton CoerceValue value is 68.9506415384615
LocalBaseBindingExpress.MyButton OnValueChanged new value is 68.9506415384615
MyButton ValidateValue value is 69.4235769230769
LocalBaseBindingExpress.MyButton CoerceValue value is 69.4235769230769
LocalBaseBindingExpress.MyButton OnValueChanged new value is 69.4235769230769
MyButton ValidateValue value is 69.9157046153846
LocalBaseBindingExpress.MyButton CoerceValue value is 69.9157046153846
LocalBaseBindingExpress.MyButton OnValueChanged new value is 69.9157046153846
MyButton ValidateValue value is 70.3990276923077
LocalBaseBindingExpress.MyButton CoerceValue value is 70.3990276923077
LocalBaseBindingExpress.MyButton OnValueChanged new value is 70.3990276923077
MyButton ValidateValue value is 70.8701507692308
LocalBaseBindingExpress.MyButton CoerceValue value is 70.8701507692308
LocalBaseBindingExpress.MyButton OnValueChanged new value is 70.8701507692308
MyButton ValidateValue value is 72.0757861538462
LocalBaseBindingExpress.MyButton CoerceValue value is 72.0757861538462
LocalBaseBindingExpress.MyButton OnValueChanged new value is 72.0757861538462
从上边可以看出,依赖属性的值当前是动画形成的值,但是这些值和直接从BaseValue中或者Binding中获取的值一样,都要通过Validate检查和Coerce的检查,然后获得依赖属性的最终值。
1.4 结论
从上边的几个实验来看,依赖属性值的最终的确认,可以用如下的图来描述,下图来自http://www.cnblogs.com/KnightsWarrior/archive/2010/08/27/1809739.html
![]()
但是个人认为,可能下图更符合我的思维方式,其中ValueSource的一系列标识量都是为了在程序中获取Value的时候,速度更加快而设计的。
(原创)2. WPF中的依赖属性之二的更多相关文章
- WPF中的依赖属性
1. WPF中的依赖属性 依赖属性是专门基于WPF创建的.在WPF库实现中,依赖属性使用普通的C#属性进行了包装,使用方法与普通的属性是相同的. 1.1 依赖属性提供的属性功能 资源 数据绑定 样式 ...
- 在WPF中使用依赖注入的方式创建视图
在WPF中使用依赖注入的方式创建视图 0x00 问题的产生 互联网时代桌面开发真是越来越少了,很多应用都转到了浏览器端和移动智能终端,相应的软件开发上的新技术应用到桌面开发的文章也很少.我之前主要做W ...
- WPF学习笔记——依赖属性(Dependency Property)
1.什么是依赖属性 依赖属性是一种可以自己没有值,并且通过Binding从数据源获得值(依赖在别人身上)的属性,拥有依赖属性的对象被称为"依赖对象". 依赖项属性通过调用 Regi ...
- [No000012D]WPF(5/7)依赖属性
介绍 WPF带来了很多传统 Windows 应用程序没有的新特性和选择.我们已经讨论了一些 WPF 的特性,是时候更进一步介绍其他特性了.当你读完这个系列之前的文章,我希望你已经或多或少地了解了 WP ...
- WPF 精修篇 依赖属性
原文:WPF 精修篇 依赖属性 依赖属性使用场景 1. 希望可在样式中设置属性. 2. 希望属性支持数据绑定. 3. 希望可使用动态资源引用设置属性. 4. 希望从元素树中的父元素自动继承属性值. 5 ...
- ReferentialConstraint 中的依赖属性映射到由存储生成的列
ReferentialConstraint 中的依赖属性映射到由存储生成的列 这个问题是由于从表中的外键关系建立错误(可能是由于误改),查看从表的所有外键关系,即可找到问题所在. 问题: 什么是从表? ...
- Entity Framework问题:ReferentialConstraint 中的依赖属性映射由存储生成的列
原文:Entity Framework问题:ReferentialConstraint 中的依赖属性映射由存储生成的列 今天在采用Entity Framework 的Database First反向以 ...
- dotnetcore3.1 WPF 中使用依赖注入
dotnetcore3.1 WPF 中使用依赖注入 Intro 在 ASP.NET Core 中默认就已经集成了依赖注入,最近把 DbTool 迁移到了 WPF dotnetcore 3.1, 在 W ...
- 【转】WPF中的Binding技巧(二)
WPF中的Binding技巧(二) 接上篇, 我们来看一看Elementname,Source,RelativeSource 三种绑定的方式 1.ElementName顾名思义就是根据Ui元素 ...
随机推荐
- SAM-Toy Cars题解
题目描述 Jasio 是一个三岁的小男孩,他最喜欢玩玩具了,他有n 个不同的玩具,它们都被放在了很高的架子上所以Jasio 拿不到它们. 为了让他的房间有足够的空间,在任何时刻地板上都不会有超过k 个 ...
- MVC – 4.mvc初体验(1)
1.MVC请求模式 2.MVC简单请求流程图 展开 折叠 3.返回string的mvc方法 展开 折叠 4.加载视图的方法
- RSA私钥和公钥文件格式 (pkcs#1, pkcs#8, pkcs#12, pem)
RSA私钥和公钥文件格式 (pkcs#1, pkcs#8, pkcs#12, pem) 2018年03月07日 11:57:22 阅读数:674 Format Name Description PKC ...
- Unity Shader 之 渲染流水线
Unity Shader 之渲染流水线 什么是渲染流水线 一个渲染流程分成3个步骤: 应用阶段(Application stage) 几何阶段(Geometry stage) 光栅化阶段(Raster ...
- Matrix-tree定理 spoj HIGH
Matrix-tree定理,给出一个无向图,问求出的生成树方案有多少种方案,利用Matrix-tree定理,主对角线第i行是i的度数,(i,j) 值为i和j之间边的数量,然后删去第一行第一列,利用初等 ...
- 2017-2018-1 JAVA实验站 第四、五周作业
2017-2018-1 JAVA实验站 第四.五周作业 JAVA实验站小组成员 学号 名字 职务 20162318 张泰毓 组长 20162303 石亚鑫 组员 20162304 张浩林 组员 201 ...
- Redis 锁的实现方案
开发中不可避免的是碰到并发请求,在数据严谨性的要求不高时,我们也不需要做什么处理,但如果碰到数据严谨性非常高的时候(例如:用户金额,秒杀产品的库存...),我们就需要慎重处理了. 解决方案多种多样,下 ...
- poj 1984 并查集
题目意思是一个图中,只有上下左右四个方向的边.给出这样的一些边, 求任意指定的2个节点之间的距离. 就是看不懂,怎么破 /* POJ 1984 并查集 */ #include <stdio.h& ...
- SQL的in的参数化查询
SqlCommand cmd=con.CreateCommand(); cmd.CommandText="exec('select * from novel where novelid in ...
- HDU 4618 Palindrome Sub-Array 暴力
Palindrome Sub-Array 题目连接: http://acm.hdu.edu.cn/showproblem.php?pid=4618 Description A palindrome s ...