[XAML]类似WPF绑定的Binding的读取方法
在WPF的XAML里,依赖属性可以使用基于BindingBase之类的MarkupExtensin
读取XAML时,会自动的把该BindingBase转换为BindingExpressionBase
然后再放入DependencyObject的EffectiveValueEntry里
那么问题来了,在我们自己做一个轻量级依赖框架时,为什么读取BindingBase会报错
假设,一个属性名称为Title,类型为string
XAML文档为
<Page xmlns="http://schemas.wodsoft.com/web/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="{Binding Content, ElementName=source}">
<ContentControl Name="source" Content="Test"/>
</Page>
在该轻量级框架里
Binding和WPF的一样
在ProvideValue方法执行时,同样会返回BindingExpression
如果读取该XAML,则会报错
类型“Wodsoft.Web.Data.BindingExpression”的对象无法转换为类型“System.String”。
因为XAML读取器会使用CLR来赋值,即使用Title属性的Setter来赋值
显然,BindingExpression无法给Title直接赋值
那么WPF是如何办到的呢?
也许你用过WPF的XamlReader,位于System.Windows.Markup下
该类的静态方法Load能读取XAML内容
同样也能正确读取Binding等MarkupExtension
该方法核心用到XamlXmlReader与XamlObjectWriter
一个读取XAML内容,一个把XAML内容变成Object
我们现在就要通过这两个类实现我们的需求
首先实现一个ObjectReader
public class ObjectReader
{
public static object Load(Stream stream)
{
XamlXmlReader reader = new XamlXmlReader(stream);
XamlObjectWriter writer = new ObjectWriter(); while (reader.Read())
{
writer.WriteNode(reader);
} writer.Close();
return writer.Result;
}
}
XamlXmlReader就用原本的Reader
它负责读取XAML文档内容
我们要写一个ObjectWriter,继承自XamlObjectWriter
在里面实现我们的依赖系统
public class ObjectWriter : XamlObjectWriter
{
public ObjectWriter() : base(new XamlSchemaContext()) { }
object _Instance;
protected override void OnBeforeProperties(object value)
{
_Instance = value;
base.OnBeforeProperties(value);
}
//设置属性值
protected override bool OnSetValue(object eventSender, XamlMember member, object value)
{
if (eventSender is DependencyObject)
{
//获取依赖属性
DependencyProperty dp = DependencyProperty.FromName(member.Name, member.DeclaringType.UnderlyingType);
if (dp == null)
{
//如果不是依赖属性,则使用CLR方法赋值
return base.OnSetValue(eventSender, member, value);
}
DependencyObject target = (DependencyObject)eventSender;
//使用自己框架的SetValue方法赋值
target.SetValue(dp, value);
return true;
}
else
return base.OnSetValue(eventSender, member, value);
} //写入成员方法
public override void WriteStartMember(XamlMember property)
{
//判断是否是依赖类型
if (property.DeclaringType != null && property.DeclaringType.UnderlyingType.IsSubclassOf(typeof(DependencyObject)))
{
//如果是属性
if (property.UnderlyingMember is PropertyInfo)
{
//防止目标类型未调用静态构造函数
//这里我不知道还有什么方法可以引发类型的静态构造函数
if (_Instance == null)
_Instance = Activator.CreateInstance(property.DeclaringType.UnderlyingType);
//获取依赖属性
DependencyProperty dp = DependencyProperty.FromName(property.Name, property.DeclaringType.UnderlyingType);
if (dp != null)
{
//如果是依赖属性
//覆盖XamlMember
//使用我们自己MemberInvoker
property = new XamlMember((PropertyInfo)property.UnderlyingMember, SchemaContext, new ObjectMemberInvoker(dp));
}
}
}
base.WriteStartMember(property);
} private object _Instance;
private bool _IsDependencyObject;
}
OnSetValue方法是设置普通值类型的属性时用到的
WriteStartMember则是当非值类型属性时调用到
这里需要编写一个ObjectMemberInvoker,继承自XamlMemberInvoker
我们需要重写GetValue和SetValue方法
这样我们就能达到我们的目标了
public class ObjectMemberInvoker : XamlMemberInvoker
{
public ObjectMemberInvoker(DependencyProperty property)
{
Property = property;
} public DependencyProperty Property { get; private set; } public override object GetValue(object instance)
{
DependencyObject d = (DependencyObject)instance;
return d.GetValue(Property);
} public override void SetValue(object instance, object value)
{
DependencyObject d = (DependencyObject)instance;
if (value is BindingExpression)
{
//...
}
else
d.SetValue(Property, value);
}
}
在SetValue方法里判断value
如果是绑定类则调用相关方法
否则调用依赖属性的设置方法
现在我们就能正常读取绑定而不会报错了
结束语
XAML很强大,可以扩展出很多东西
但是里面有很多东西微软是没有开放的
拿来做框架会遇到很多坑
甚至于没有解决方法
更多出现于VS的XAML编辑器里
比如这个问题
http://stackoverflow.com/questions/18671317/each-dictionary-entry-must-have-an-associated-key
这个BUG已经有人报告给VS团队并通过了
但至今未解决……
[XAML]类似WPF绑定的Binding的读取方法的更多相关文章
- WPF 绑定属性 XAML 时间格式化
原文:WPF 绑定属性 XAML 时间格式化 XAML 时间格式化{Binding Birthday,StringFormat='yyyy-MM-dd '} public class AssetCla ...
- WPF绑定xaml中绑定对象需用属性表示,字段不可以绑定
在练习WPF绑定时发现对象属性可以在XAML中绑定,但字段是不可以绑定: 比如: private Person person{get;set;} 可以绑定到XAML中,<TextBox Nam ...
- WPF快速入门系列(4)——深入解析WPF绑定
一.引言 WPF绑定使得原本需要多行代码实现的功能,现在只需要简单的XAML代码就可以完成之前多行后台代码实现的功能.WPF绑定可以理解为一种关系,该关系告诉WPF从一个源对象提取一些信息,并将这些信 ...
- 【转】【WPF】WPF绑定用法
一.简介 为了后面行文顺利,在进入正文之前,我们首先对本文所涉及到的绑定知识进行简单地介绍.该节包含绑定的基本组成以及构建方式. WPF中的绑定完成了绑定源和绑定目标的联动.一个绑定常常由四部分组成: ...
- WPF入门教程系列(二) 深入剖析WPF Binding的使用方法
WPF入门教程系列(二) 深入剖析WPF Binding的使用方法 同一个对象(特指System.Windows.DependencyObject的子类)的同一种属性(特指DependencyProp ...
- 【转】WPF中的Binding技巧(二)
WPF中的Binding技巧(二) 接上篇, 我们来看一看Elementname,Source,RelativeSource 三种绑定的方式 1.ElementName顾名思义就是根据Ui元素 ...
- WPF 绑定
WPF里分三种Binding:Binding, PriorityBinding, MultiBinding,这三种Binding的基类都是BindingBase,而BindingBase又继承于Mar ...
- WPF 绑定StaticResource到控件的方法
原文:WPF 绑定StaticResource到控件的方法 资源文件内的属性能否直接通过绑定应用到控件?答案是肯定的. 比如,我们要直接把下面的<SolidColorBrush x:Key=&q ...
- WPF - 绑定及惯用法(一)
写在前面:这仍然是一些没有经过严格审阅的文字.虽然我的确执行了初稿.复稿以及审阅等一系列用以保证文章质量的方法,但是仍然担心其中是否有错误.希望您能帮助指出,以在下一次我在版本更新时进行修正.所有的错 ...
随机推荐
- mac 关闭&&显示隐藏文件命令
打开终端,输入: defaults write com.apple.finder AppleShowAllFiles -bool true 此命令显示隐藏文件 defaults write com.a ...
- angular路由详解:
1.$routeProvider ngRoute模块中的服务 2.otherwise:设置用于路由改变时,与任何其他定义的路由无法匹配的时候执行的代码 3.when:为$route服务定义新的路由 例 ...
- asp.net 文件下载(txt,rar,pdf,word,excel,ppt)
aspx 文件下载说起来一点都不难,但是在做的过程中还是遇到了一些小小的问题,就是因为这些小小的问题,导致解决起来实在是太难了,其中一个就是Response.End();导致下载文件出现线程终止的情况 ...
- 第一章 简单工厂模式 及 UML中类图的表示方法
写一个简单计算器程序时,可以写一个操作类,然后加.减.乘.除操作分别继承它,复写操作计算结果的方法.写一个简单工厂类,通过输入的操作符,使用操作类来new一个相应的操作类的子类对象.这样,工厂就实例化 ...
- socket泄露的问题
在增加keepalive和libevent 超时后,仍然会几个月后出现lsof统计句柄过多的问题,如下图,红线圈定的是不定期出现的错误关闭流,时间点和server端日志(只看到accpet fd,没有 ...
- 小米4 miui专用 Xposed安装器86版
转载自 http://www.52pojie.cn/thread-516435-1-1.html 写在前面:各位用xp受到不同限制,有些机型还找不到框架包,又要刷第三方rec又要谨慎选择框架版本.官方 ...
- vmware 下centos7配置网络
步骤一: 虚拟机中的网络设置配置为桥接模式: 步骤二: 注:本人配置的为非静态IP,ip为自动获取 vi /etc/sysconfig/network-scripts/ifcfg-eth0 配置内容如 ...
- centos安装tmux过程
原文:https://gist.github.com/rothgar/cecfbd74597cc35a6018 # Install tmux on Centos release 6.5 # insta ...
- Python ToDo List
这是我在学习python过程中,想做又没来得及做的事情一览.最初只有寥寥几个字,我会尽力去消化,让它不会只增不减. 由于博客园奇怪的算法,明明是一篇非常没有含量的东西(连字数都没有达到),居然能荣登p ...
- python学习笔记(5)--迭代器,生成器,装饰器,常用模块,序列化
生成器 在Python中,一边循环一边计算的机制,称为生成器:generator. 如: >>> g = (x * x for xin range(10)) >>> ...