[.NET] XAML(1)--物件生成
前言
XAML是微软推出的一种宣告式标记语言,采用XML的格式让开发人员设计应用程序编程接口。在微软近期推出的各种开发平台,例如WPF、Silverlight、WP7、甚至Win8的Metro style app开发上都可以看到XAML的身影。XAML可以这么的神奇的跨平台运作,是因为XAML不涉足执行平台的运作、机制...等等,只单纯的依照开发人员的设计,建立对应的对象让执行平台使用。例如:
XAML范例
1 2 3 4 5 6 7 8 9 10 11 12 | < phone:PhoneApplicationPage x:Class="XamlSample.MainPage" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d" d:DesignWidth="480" d:DesignHeight="800"> < TextBlock x:Name="ShowTextBlock" Text="Hello World" FontSize="72"/> </ phone:PhoneApplicationPage > |
1 2 3 4 5 6 7 8 9 10 11 | namespace XamlSample { public partial class MainPage : PhoneApplicationPage { public MainPage() { // Base InitializeComponent(); } } } |
Code范例
1 2 3 4 5 6 7 8 9 10 | < phone:PhoneApplicationPage x:Class="XamlSample.MainPage" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d" d:DesignWidth="480" d:DesignHeight="800"> </ phone:PhoneApplicationPage > |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | namespace XamlSample { public partial class MainPage : PhoneApplicationPage { public MainPage() { // Base InitializeComponent(); // Create TextBlock showTextBlock = new TextBlock(); showTextBlock.Name = "ShowTextBlock" ; showTextBlock.Text = "Hello World" ; showTextBlock.FontSize = 72; this .Content = showTextBlock; } } } |
执行结果
这两个WP7的范例程序,执行结果都是在画面上显示Hello World。而我们在程序代码里加入断点,来检视执行结果的对象(如下图),可以看出两个范例最终产生的对象结构是相同的。也就是说,不管是使用XAML或是使用程序代码的方式来建构画面对象都是相同的。.NET会依照开发人员设计的XAML内容建立对象,就像是开发人员使用程序代码建立对象一样。理解这个范例之后,可以简单的说,XAML是用来产生对象的配置文件、执行平台使用XAML产生的对象。而.NET依照设定来产生对象是采用Reflection,我们也可以更广义的说「XAML是用来产生对象的Reflection配置文件」。
XAML范例中断
Code范例中断
本篇文章采用「XAML是用来产生对象的Reflection配置文件」,这样的角度剖析XAML。来辅助开发人员理解XAML,并且知道是如何透过XAML来产生对象。
Object-Element
下面这段XAML,代表一个TextBlock对象。当程序执行的时候,.NET会剖析XAML Element来产生一个TextBlock对象。像这样会产生一个对象的XAML Element称为「Object-Element」。
1 | < sample:TextBlock x:Name="ShowTextBlock" Text="Hello World" FontSize="72" xmlns:sample="clr-namespace:System.Windows.Controls;assembly=System.Windows" /> |
有用过Reflection的开发人员,会知道组件名称、命名空间、类别名称,有这三项字符串数据就可以反射生成一个对象出来。在Object-Element里,这三项数据也有各自设定的规范。依照XAML的规范来解读上面这个Object Element,可以得到:「组件名称」是System.Windows、「命名空间」是System.Windows.Controls、「类别名称」则是TextBlock。.NET剖析Object Element之后,就会依照这些字符串数据,反射生成出一个TextBlock对象。将这个XAML Element取代Hello World范例里的TextBlock依然可以正常的显示Hello World。
1 2 3 4 5 6 7 8 9 10 11 12 | < phone:PhoneApplicationPage x:Class="XamlSample.MainPage" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d" d:DesignWidth="480" d:DesignHeight="800"> < sample:TextBlock x:Name="ShowTextBlock" Text="Hello World" FontSize="72" xmlns:sample="clr-namespace:System.Windows.Controls;assembly=System.Windows" /> </ phone:PhoneApplicationPage > |
当然这样的XAML内容,看起来跟一般常见的XAML有所出入,一整个复杂了许多。因为XAML是由XML发展出来的,很多的格式沿用XML的规范。许多命名空间可以由上层的Element所提供,这样的规范大量减少XAML需要设定的数据内容。这部分有兴趣的开发人员可以参考XML的相关技术资料。另外各种开发平台也定义了一些默认的关键词,让XAML的设计可以变得更简洁,这部分有兴趣的开发人员可以参考开发平台的相关技术资料。以上面这个范例来说,因为是要产生开发平台预设的TextBlock,而这个开发平台预设的命名空间已经在PhoneApplicationPage做过宣告,所以可以将组件名称、命名空间都省略掉。XAML经过这些规范的简化之后,就可以产生出一般常见的XAML数据内容。
Property-Attribute
下面这段XAML,代表一个TextBlock对象, TextBlock对象有一个Text属性。当程序执行的时候,.NET会剖析XAML Element来产生一个TextBlock对象,并且将这个TextBlock对象的Text属性设定为Hello World、FontSize属性设定为72。像这样会设定一个对象属性的设定,称为「Property-Attribute」。
1 | < TextBlock x:Name="ShowTextBlock" Text="Hello World" FontSize="72"/> |
查询MSDN可以发现TextBlock的FontSize属性,是一个型别为System.Double的属性。而XAML因为是XML的格式,所以被限制了只能输入字符串形式的数据。受于这样的限制,.NET剖析Property-Attribute的时候,会尝试将字符串数据转型为对象属性的型别。以下面这个范例来说,在执行的阶段会看到.NET的错误通知,告知无法将字符串数据转型为System.Double。
1 | < TextBlock x:Name="ShowTextBlock" Text="Hello World" FontSize="72Clark"/> |
Property-Element
在XAML的规范里,Property-Attribute章节里的TextBlock范例,也可以写成下面范例的格式。将TextBlock的FontSize属性改写成为一对独立的标签,并且设定值写在标签的内容里。像这样设定一个对象属性的设定,称为「Property-Element」。
1 2 3 4 5 | < TextBlock x:Name="ShowTextBlock" Text="Hello World" > < TextBlock.FontSize > 72 </ TextBlock.FontSize > </ TextBlock > |
Property-Element的写法看起来有点多余,但其实这是为了XAML的延展性而设计。一般对象的属性有些不单纯是int、double这些实值型别,也有可能是一个对象(Class)、一个结构(Struct)。而一个对象又会有属性,整个对象就是以树状结构生长下去。这时Property-Attribute使用字符串来设定这个对象树状结构会显得力不从心。Property-Element定义了,可以使用Object-Element来当作内容来解决这个问题。.NET在剖析Property-Element的时候,会将Object-Element内容反射生成出对应的对象,设定为对象的对象属性。而使用Object-Element来当作Property-Element的内容另一个原因是,Object-Element自己是描述一个对象,它又可以拥有自己的Property-Attribute、Property-Element,这样就可以一层一层设计出对象的树状结构。
下面这段XAML,采用Property-Element来设定TextBlock对象的Foreground属性。而TextBlock对象的Foreground属性,是一个型别为Brush的对象属性。所以在Property-Element里采用Object-Element来生成要设定给Foreground属性的一个Brush对象。
1 2 3 4 5 | < TextBlock x:Name="ShowTextBlock" Text="Hello World" FontSize="72"> < TextBlock.Foreground > < SolidColorBrush Color="#FF0000" /> </ TextBlock.Foreground > </ TextBlock > |
仔细看上面的范例,会发现并不是生成一个Brush对象,而是生成Brush的延伸对象SolidColorBrush。这是因为Brush对象是一个抽象类,并没有办法直接生成。所以只能生成延伸自Brush的SolidColorBrush来当作Foreground属性的对象。这也就是说,我们可以生成延伸类别来设定对象属性。这是一个面向对象开发很重要的功能,提供了开发人员抽换对象的能力,大幅增加系统对象的弹性。
Property-Element-Collection
既然一般对象的属性不单纯是int、double这些实值型别,有可能是一个对象(Class)、一个结构(Struct)。就免不了的对象的属性,也有可能是对象、结构的集合(Collection)。Property-Element另外也定义了,可以使用多个Object-Element来当作内容来解决这个问题。.NET在剖析Property-Element的时候,会将多个Object-Element内容反射生成出对应的对象,并且加入对象的对象集合属性。
下面这段XAML,采用Property-Element来设定LinearGradientBrush对象的GradientStops属性。而LinearGradientBrush对象的GradientStops属性,是一个GradientStop型别的对象集合属性。所以在Property-Element里采用多个Object-Element,来生成要设定给GradientStops属性的多个GradientStop对象。
1 2 3 4 5 6 7 8 9 10 11 | < TextBlock x:Name="ShowTextBlock" Text="Hello World" FontSize="72"> < TextBlock.Foreground > < LinearGradientBrush StartPoint="0,1" EndPoint="1,0" > < LinearGradientBrush.GradientStops > < GradientStop Color="#FF0000" Offset="0.0"/> < GradientStop Color="#00FF00" Offset="0.5"/> < GradientStop Color="#0000FF" Offset="1.0"/> </ LinearGradientBrush.GradientStops > </ LinearGradientBrush > </ TextBlock.Foreground > </ TextBlock > |
后记
了解XAML的对象生成,在学习WPF、Silverlight、WP7等等开发平台的时候,就可以参考MSDN类别库资料来查询透过XAML生成的对象。了解对象本身的职责及工作内容,以及设定每个属性会让对象发生何种变化。这样从对象本身开始学习的路线,会比较正确而且快速、并且不会被过多繁杂的变化所迷惑。
期許自己~
能以更簡潔的文字與程式碼,傳達出程式設計背後的精神。
真正做到「以形寫神」的境界。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
· DeepSeek如何颠覆传统软件测试?测试工程师会被淘汰吗?