在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的读取方法的更多相关文章

  1. WPF 绑定属性 XAML 时间格式化

    原文:WPF 绑定属性 XAML 时间格式化 XAML 时间格式化{Binding Birthday,StringFormat='yyyy-MM-dd '} public class AssetCla ...

  2. WPF绑定xaml中绑定对象需用属性表示,字段不可以绑定

    在练习WPF绑定时发现对象属性可以在XAML中绑定,但字段是不可以绑定: 比如: private Person person{get;set;}  可以绑定到XAML中,<TextBox Nam ...

  3. WPF快速入门系列(4)——深入解析WPF绑定

    一.引言 WPF绑定使得原本需要多行代码实现的功能,现在只需要简单的XAML代码就可以完成之前多行后台代码实现的功能.WPF绑定可以理解为一种关系,该关系告诉WPF从一个源对象提取一些信息,并将这些信 ...

  4. 【转】【WPF】WPF绑定用法

    一.简介 为了后面行文顺利,在进入正文之前,我们首先对本文所涉及到的绑定知识进行简单地介绍.该节包含绑定的基本组成以及构建方式. WPF中的绑定完成了绑定源和绑定目标的联动.一个绑定常常由四部分组成: ...

  5. WPF入门教程系列(二) 深入剖析WPF Binding的使用方法

    WPF入门教程系列(二) 深入剖析WPF Binding的使用方法 同一个对象(特指System.Windows.DependencyObject的子类)的同一种属性(特指DependencyProp ...

  6. 【转】WPF中的Binding技巧(二)

    WPF中的Binding技巧(二)     接上篇, 我们来看一看Elementname,Source,RelativeSource 三种绑定的方式 1.ElementName顾名思义就是根据Ui元素 ...

  7. WPF 绑定

    WPF里分三种Binding:Binding, PriorityBinding, MultiBinding,这三种Binding的基类都是BindingBase,而BindingBase又继承于Mar ...

  8. WPF 绑定StaticResource到控件的方法

    原文:WPF 绑定StaticResource到控件的方法 资源文件内的属性能否直接通过绑定应用到控件?答案是肯定的. 比如,我们要直接把下面的<SolidColorBrush x:Key=&q ...

  9. WPF - 绑定及惯用法(一)

    写在前面:这仍然是一些没有经过严格审阅的文字.虽然我的确执行了初稿.复稿以及审阅等一系列用以保证文章质量的方法,但是仍然担心其中是否有错误.希望您能帮助指出,以在下一次我在版本更新时进行修正.所有的错 ...

随机推荐

  1. 基于libvlc和wxWidgets的简单播放器代码阅读

    源代码来自 http://git.videolan.org/?p=vlc.git;a=blob_plain;f=doc/libvlc/wx_player.cpp // g++ wx_player.cp ...

  2. WPF获取应用程序启动目录的方法

    1.AppDomain.CurrentDomain.BaseDirectory using System; namespace ConsoleApplication1 { class Program ...

  3. EFUpdate

    using System; using System.Collections.Generic; using System.Configuration; using System.Data; using ...

  4. java 对象序列化与反序列化

    Java序列化与反序列化是什么? 为什么需要序列化与反序列化? 如何实现Java序列化与反序列化? 本文围绕这些问题进行了探讨. 1.Java序列化与反序列化  Java序列化是指把Java对象转换为 ...

  5. vs2012 安装entity framework

    1.安装vs2012 2.打开vs2012的工具下的扩展工具 3.搜索nuget,没安装的直接在线安装 4.安装好了NuGet,程序包管理器控制台 5.执行命令Install-Package Enti ...

  6. 如何封装JS ----》JS设计模式《------ 封装与信息隐藏

    1. 封装与 信息隐藏之间的关系 实质是同一个概念的两种表达,信息隐藏式目的,二封装是借以达到目的的技术方法.封装是对象内部的数据表现形式和实现细节,要想访问封装过额对象中的数据,只有使用自己定义的操 ...

  7. javaSE基础07

    javaSE基础07 一.static静态修饰符 用了static修饰的变量就会变成共享的属性,只会初始化一次,在内存中只存在一个,并且每个对象都可以访问,存放在方法区(数据共享区) 1.1 stat ...

  8. wget 扒站

    在Linux下,通过一个命令就可以把整个站相关的文件全部下载下来. wget -r -p -k -np [网址] 参数说明: -r : 递归下载 -p : 下载所有用于显示 HTML 页面的图片之类的 ...

  9. iOS开发CoreGraphics核心图形框架之一——CGPath的应用

    一.引言    CoreGraphics核心图形框架相较于UIKit框架更加偏于底层.在Objective-C工程中,CoreGraphics其中方法都是采用C语言风格进行编写的,同时其并不支持Obj ...

  10. KAOS模型

    问题描述: 我们开发了一种针对时序数据的文件格式TSFile,本身不支持sql查询.为了让公司分析人员能够用SQL进行分析,并且应用一些机器学习算法进行预测,需要设计并实现一个TSFile与Spark ...