Markup Extension,顾名思义,就是对xaml的扩展
在xaml中,规定如果属性以{}开始及结束,就是Markup Extension。
Markup Extension指的是继承于MarkupExtension的类。
public abstract class MarkupExtension { // Methods protected MarkupExtension(); public abstract object ProvideValue(IServiceProvider serviceProvider); }
所有继承于MarkupExtension的子类,必须覆写ProvideValue方法,该方法返回的object值用来给属性赋值同。另外约定这些继承类,必须以Extension作为类名的后缀,而在xmal中可以把Extension这个后缀省略。
如上例中的{x: Null}{x: Static …},实际上对应NullExtension和StaticExtension这两个类。
当然MarkupExtension的实现者肯定需要接收不同的参数,以返回不同的值,这样,我们要实现出不同的构造方法,比如上面的StaticExtension,其实现如下:
public class StaticExtension : MarkupExtension { // Fields private string _member; private Type _memberType; // Methods public StaticExtension(); public StaticExtension(string member); public override object ProvideValue(IServiceProvider serviceProvider); // Properties [ConstructorArgument("member")] public string Member { get; set; } internal Type MemberType { get; set; } }
这里有个构造方法接收string member为参数,ProvideValue就根据这个member返回不同的值。
那么在xaml上如何使用这个构造方法呢?
Height=”{x:Static SystemParameters.IconHeight}” ,注意x: Static后面跟着的SystemParameters.IconHeight,这个就对应StaticExtension(string member)中的member;如果有构造方法中有多个参数,需指定每个参数的名称,再为其指定值,格式如Binding中的Path=Height
WPF 编程中最常用的标记扩展是支持资源引用的标记扩展(StaticResource 和 DynamicResource)以及支持数据绑定的标记扩展 (Binding)。
1. StaticResource 通过替换已定义资源的值来为 XAML 属性提供值。
2. DynamicResource 通过将值推迟为对资源的运行时引用来为 XAML 属性提供值。动态资源引用强制在每次访问此类资源时都重新进行查找。
3. Binding 按应用于元素的数据上下文来为属性提供数据绑定值。此标记扩展相对复杂,因为它会启用大量内联语法来指定数据绑定。
4. RelativeSource 为可以在运行时元素树中定位若干可能关系的 Binding 提供源信息。对于在多用途模板中创建的绑定,或在未充分了解周围的元素树的情况下以代码创建的绑定,上述标记扩展会提供专用源。
5. TemplateBinding,控件模板可以通过它使用来自要利用该模板的类的对象模型定义属性中的模板化属性的值。有关详细信息,请参见 TemplateBinding 标记扩展。
Binding是继承于BindingBase的,而BindingBase继承于MarkupExtension,这个比较特殊。
{}的转义:
Content=”{}{This is not a markup extension!},在最前面加{}就可以实现转义
自定义Markup Extension的例子,来源于网上
internal class FileExtension : MarkupExtension { public FileExtension() { } public FileExtension(object filePath) { _filePath = filePath; } private object _filePath; /// /// Must be object type. /// public object FilePath { get { return _filePath; } set { _filePath = value; } } /// /// All Extension logic is implemented here. /// public override object ProvideValue(IServiceProvider serviceProvider) { if (_filePath == null) { return string.Empty; } try { StreamReader sr = new StreamReader(_filePath as string); return sr.ReadToEnd(); } catch (Exception e) { return e.ToString(); } } }