MarkupExtension的使用

记得第一次看到MarkupExtension是在几年前的一次面试中。很不好意思说,当时不知道是什么东东。最近在项目中又用到了WPF的这个功能,决定在博客里记录一下。

在Xaml中为某个对象以Attribute的方式设置对象的属性时,attribute的值默认只能是字符串。例如:

<TextBlock Text="Text"/>

上面为Text属性设置值"Text"。如果属性的类型为String(如上面代码中的Text属性),这是没有问题的。但是如果属性的类型不是String,比如Foreground属性,它的类型是Brush。我们发现Xaml中仍然是可以通过设置一个字符串来完属性赋值的。例如:

<TextBlock Foreground="Aqua" Text="Foreground"/>

这是因为BCL为Brush类型定义了一个TypeConverter: BrushConverter. 它会在运行时将字符串转换成一个Brush结构。如果我们要在Xaml中直接给Foreground属性传递一个Brush对象怎么办呢?这就到了MarkupExtension发挥作用的时候了。它的作用就是扩充了Attribute方式赋值时只能赋给字符串的限制。让在赋值的时候可以执行后台代码从而产生所期望的对象。其实我们经常用的Binding,StaticResource,DynamicResource等都是属于MarkupExtension. 上代码:

先看一下使用MarkupExtension后xaml的效果:

<Window x:Class="WPFSample.Samples.MarkupExtensionSample"

        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

        xmlns:me="clr-namespace:WPFSample.Samples.MarkupExtensionSamples"

        Title="MarkupExtensionSample" Height="300" Width="300">

    <Grid>

        <StackPanel>

            <TextBlock Foreground="Aqua" Text="Foreground"/>

            <!--Following xaml code set a foreground using markup extension.-->

            <TextBlock Foreground="{me:BrushGetter TitleBrush}" Text="Foreground from markup extension"/>

            <TextBlock Foreground="{me:BrushGetter ContentBrush}" Text="Foreground from markup extension"/>

        </StackPanel>

    </Grid>

</Window>

再看看BrushGetter的定义:

public class BrushGetter : MarkupExtension

    {

        private string _brushName;



        public BrushGetter(string brushName)

        {

            //在Xaml中使用该MarkupExtension时传递brushName参数。

            _brushName = brushName;

        }



        public override object ProvideValue(IServiceProvider serviceProvider)

        {

            //当在通过该MarkupExtension在Xaml中给属性赋值时,该方法将被调用。根据条件返回一个合适的对象即可。

            //至于参数serviceProvider,一般情况下用不到。暂时不纠结它了。

            switch (_brushName)

            {

                case "TitleBrush":

                    return Brushes.Black;

                case "ContentBrush":

                    return Brushes.Blue;

                default:

                    break;

            }



            return null;

        }

    }

最后看看最终效果:

image

其实使用MarkupExtension来赋值时,运行时会在每次赋值时构造一个Markup Extension对象,传递xaml中定义的参数,然后调用ProvideValue方法获取一个值。

你可能感兴趣的:(mark)