MarkupExtension:msdn上定义:
为可以由 .NET Framework XAML 服务及其 XAML 读取器和 XAML 编写器支持的 XAML 标记扩展实现提供基类。
个人使用下来的感觉有点类似于附加属性,但是附加属性是用来定义的赋值的,而该扩展类可以用来作为变量绑定附加属性或者依赖属性。
每个继承MarkupExtension的类都需要override一个方法:
public override object ProvideValue(
IServiceProvider serviceProvider)
当中参数IServiceProvider serviceProvider可以提供一个object GetService(Type serviceType);方法:
具体使用:
IProvideValueTarget ipvt = (IProvideValueTarget)serviceProvider.GetService(typeof(IProvideValueTarget)); DependencyObject targetObject = ipvt.TargetObject as DependencyObject; DependencyProperty dp = ipvt.TargetProperty as DependencyProperty;
通过该方法,可以获取绑定的控件,以及绑定的属性。
同时可以定义多个属性,以及对应的构造函数,配合设计模型需要。
public MaxValueExtensionFull(object value1, object value2) { Value1 = value1; Value2 = value2; } [ConstructorArgument("value1")] public object Value1 { get; set; } [ConstructorArgument("value2")] public object Value2 { get; set; }
好了定义了这么多,为的是什么呢?接下来可以为我们的扩展xaml添加逻辑内容了:
private object GetMaxValue() { if (Value1 is IComparable && Value1 is IComparable) { if (((IComparable)Value1).CompareTo(Value2) >= 0) return Value1; else return Value2; } else { // use val1 return Value1; } } public override object ProvideValue(IServiceProvider serviceProvider) { if (serviceProvider == null) return null; // get the target of the extension from the IServiceProvider interface IProvideValueTarget ipvt = (IProvideValueTarget)serviceProvider.GetService(typeof(IProvideValueTarget)); DependencyObject targetObject = ipvt.TargetObject as DependencyObject; object val = GetMaxValue(); if (ipvt.TargetProperty is DependencyProperty) { // target property is a DP DependencyProperty dp = ipvt.TargetProperty as DependencyProperty; if (val is IConvertible) { val = Convert.ChangeType(val, dp.PropertyType); } } else { // target property is not a DP, it's PropertyInfo instead. PropertyInfo info = ipvt.TargetProperty as PropertyInfo; if (val is IConvertible) { val = Convert.ChangeType(val, info.PropertyType); } } return val; }
刚开始这么写扩展,觉得有些多余,我可以在控件上加依赖属性,加converter转换,一样可以绑定,但是这样子的话一个控件就要一堆属性和converter,代码冗余。
而使用扩展后,我只需要定义一个Extension,那么就可以在所有控件上都使用了。