[.NET] XAML(2)--标签扩充

前言

在前一个章节[.NET] XAML(1)--对象生成,介绍了「XAML对象生成」这个简单却强大的对象生成模式。透过这个XAML对象生成配合面向对象的对象设计,可以让开发人员依照XAML内容生成近乎无限组合的对象。但是光只有前一个章节介绍的内容,在实际的开发应用上,很快就会遇到不足的地方。

 

假设现在要使用Property-Element的设定,将TextBlock 的Text设定为.NET里的Null,开发人员可能会写出下面范例的XAML。

 

<TextBlock x:Name="ShowTextBlock" FontSize="72">
    <TextBlock.Text>
        Null
    </TextBlock.Text>
</TextBlock>

 

这段XAML乍看之下很合理,但是照前一章的运作逻辑去做分析。.NET剖析XAML Element来产生对象的时候,会将"Null"转换为字符串,而不会是开发人员预期的.NET里面的Null。由这一个简单的范例来理解,就可以发现Property-Attribute、Property-Element…等等,的确是有语意不足的地方。

 

 

Markup Extensions

为了补足Property-Attribute、Property-Element这些设定语意不足的地方,XAML另外提供了「标记延伸」(Markup Extensions)这个设定,来满足开发人员的需求。Markup Extensions的运作逻辑,主要是围绕在MarkupExtension这个Class身上。

 

当程序使用.NET剖析XAML Object-Element建立对象的时候,会特别去检查建立出来的对象,是不是继承自MarkupExtension的子对象型别。当发现建立的对象是继承自MarkupExtension的子对象型别,.NET不会用这个对象当作Object-Element建立的结果,而是改呼叫这个对象继承与覆写的MarkupExtension的ProvideValue方法。并且使用ProvideValue方法的回传值,当作Object-Element建立的结果对象。

 

我们可以建立范例,来验证Markup Extensions的运作逻辑。首先建立一个继承自MarkupExtension的子对象类别ClarkExtension,并且覆写继承自MarkupExtension的ProvideValue方法。在这个范例里,ClarkExtension的ProvideValue方法只是单纯的回传一个"Clark"字符串。

 

using System;
using System.Windows.Markup;
using System.Windows.Media;

namespace WpfApplication2
{
    public class ClarkExtension : MarkupExtension
    {
        public ClarkExtension()
        {

        }

        public override object ProvideValue(IServiceProvider serviceProvider)
        {
            return "Clark";
        }
    }
}

 

接着建立XAML范例,来使用ClarkExtension这个Class。下面这段XAML,采用Property-Element来将ClarkExtension,设定为TextBlock对象的Text属性。

 

<Window x:Class="WpfApplication2.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:sample="clr-namespace:WpfApplication2"
        Title="MainWindow" Height="400" Width="240">
    
    <TextBlock x:Name="ShowTextBlock" FontSize="72">
        <TextBlock.Text>
            <sample:ClarkExtension />
        </TextBlock.Text>
    </TextBlock>
    
</Window>

 

将这个范例编译执行,并且在程序代码里加入断点来检视对象执行的顺序。可以发现的确是执行了ClarkExtension的建构子之后,就呼叫ProvideValue、回传Clark字符串。并且在执行之后,将Clark字符串设定为TextBlock 的Text内容,这样最终程序呈现的执行结果就会如下图。透过这个范例,开发人员可以简单验证与理解XAML的 Markup Extensions运作逻辑。

 

 

相关数据可以参考:
http://msdn.microsoft.com/zh-tw/library/ee855815.aspx
http://msdn.microsoft.com/zh-tw/library/system.windows.markup.markupextension.aspx

 

简化语法

上一个章节XAML范例里的Markup Extensions设定,看起来跟一般常见的XAML上的Markup Extensions有所出入,一整个复杂了许多,这对于开发人员来说并不是很友善的设计。为了降低复杂度及提高可读性,XAML另外加入了简化的语法设定,让XAML的设计可以变得更简洁。

 

首先XAML定义了MarkupExtension对象,可以省略撰写Extension后置字符。以上一个章节的范例来说,可以将范例XAML里的TextBlock简化设定为:

 

<TextBlock x:Name="ShowTextBlock" FontSize="72">
    <TextBlock.Text>
        <sample:Clark />
    </TextBlock.Text>
</TextBlock>

 

另外使用Property-Attribute设定的时候,XAML也定义使用大括号 ({...}),来识别MarkupExtension对象。以上一个章节的范例来说,可以将范例XAML里的TextBlock简化设定为:

 

<TextBlock x:Name="ShowTextBlock" FontSize="72" Text="{sample:ClarkExtension}"/>

 

当然啦,这两个简化的规则是可以互相组合的。以上一个章节的范例来说,可以将范例XAML里的TextBlock简化设定为如下的结果。这样的简化结果,就是一般常见的XAML设定。

 

<TextBlock x:Name="ShowTextBlock" FontSize="72" Text="{sample:Clark}"/>

 

相关数据可以参考:
http://msdn.microsoft.com/zh-tw/library/ee855815.aspx#naming_the_support_type
http://msdn.microsoft.com/zh-tw/library/ms788723.aspx#markup_extensions

 

XAML 定义标记延伸

在XAML内对于一些常见的的使用情景,预先实做了几个MarkupExtension子对象。这些预设的MarkupExtension子对象,通常放在System.Xaml组件的System.Windows.Markup命名空间内。在使用Visual Studio建立XAML相关页面的时候,要引用这些MarkupExtension子对象,预设是以「x: 前导符」来加以引用。几个比较常见的XAML MarkupExtension如下:

 

x:Type (TypeExtension)
TypeExtension会剖析设定的参数数据,回传对应的 Type对象。

 

x:Static(StaticExtension)
StaticExtension会剖析设定的参数数据,回传对应的对象的静态属性。

 

x:Null(NullExtension)
NullExtension没有需要设定的参数数据,就只是单纯的回传.NET的Null物件。

 

更多的数据可以参考:
http://msdn.microsoft.com/zh-tw/library/ms747254.aspx#XAML_Defined_Markup_Extensions

 

后记

XAML的Markup Extensions这个设定,是一些WPF、Silverlight、WP7功能(数据系结、资源参考)的运作核心。先理解Markup Extensions这个运作核心的职责及工作内容,再去学习数据系结、资源参考功能。这样从运作核心本身开始学习的路线,会比较正确而且快速、并且不会被过多繁杂的变化所迷惑。

 

补充

XAML在WPF、Silverlight、WP7都可以使用,但不同目标平台所开放、支持的函式库却不一定相同。以本章说明的StaticExtension来说,这个MarkupExtension类别在WPF上有支持,但在WP7上却是不支持的(撰写本文时,开发环境安装的是Windows Phone SDK 7.1)。开发人员在撰写XAML的时候,先确认目标平台支持的函式库相关内容,可以减少一些开发上不必要的困扰。


posted @ 2012-04-21 15:06  Clark159  阅读(1257)  评论(0编辑  收藏  举报