WPF MarkupExtension 原理
存在一些不是特定于XAML的WPF实现的标记扩展,而是XAML作为语言的内在函数或特征的实现。这些标记扩展在System.Xaml程序集中实现,作为一般.NET Framework XAML服务的一部分,并且位于XAML语言XAML命名空间内。在Xaml中为某个对象以Attribute的方式设置对象的属性时,attribute的值默认只能是字符串。
例如:
1 | <TextBlock Text="Text"/> |
上面为Text属性设置值”Text”。如果属性的类型为String(如上面代码中的Text属性),这是没有问题的。但是如果属性的类型不是String,比如Foreground属性,它的类型是Brush。我们发现Xaml中仍然是可以通过设置一个字符串来完属性赋值的。例如:
1 | <TextBlock Foreground="Aqua" Text="Foreground"/> |
这是因为BCL为Brush类型定义了一个TypeConverter: BrushConverter. 它会在运行时将字符串转换成一个Brush结构。如果我们要在Xaml中直接给Foreground属性传递一个Brush对象怎么办呢?这就到了MarkupExtension发挥作用的时候了。它的作用就是扩充了Attribute方式赋值时只能赋给字符串的限制。让在赋值的时候可以执行后台代码从而产生所期望的对象。其实我们经常用的Binding,StaticResource,DynamicResource等都是属于MarkupExtension. 上代码:
先看一下使用MarkupExtension后xaml的效果:
1 | <Window x:Class="WPFSample.Samples.MarkupExtensionSample" |
再看看BrushGetter的定义:
1 | public class BrushGetter : MarkupExtension |
其实使用MarkupExtension来赋值时,运行时会在每次赋值时构造一个Markup Extension对象,传递xaml中定义的参数,然后调用ProvideValue方法获取一个值。