零起点学习WPF之《WPF揭秘》读书笔记(3)
2.8 编译:将XAML代码与过程式代码混合使用。【数据绑定特性 和 触发器】
2.8.1在运行时加载和解析XAML
WPF的运行时XAML解释器公开为两个类,他们都在System.Windows.Markup命名空间下,分别为:XamlReader和XamlWriter 。XamlReader中包含一些Load方法的重载,XamlWriter包含一些Save方法的重载。
(1)XamlReader
XamlReader .Load 方法的设置将解析Xaml,创建合适的.NET对象,然后返回一个根元素的实例。
例如:在当前的目录中有一个一个名为:MyWindows.xaml,它包含一个Window对象作为根节点,那么可以使用下面的代码来加载和获取Windows对象。
Window window =null;
Using(FileStream fs = newFileStream("MyWindow.xaml"),FileMode.Open,FileAccess.Read)
{
window =(Window)XamlReader.Load(fs);//获得根元素
}
在上述的情况下:Load与FileStream 一起被调用的。在load返回之后,整个XAML文件的对象层级将在内存中被实例化,因此就不在需要XAML文件了。
【提示】XamlReader 也提供了LoadAsync方法,用以异步加载和解析XAML文档,CancelAsync和Completeted方法用以辅助LoadAsync方法。
既然有一个根对象元素的实例存在,就可以利用适当的内容元素或者是集合元素,下面的代码假设Window有一个类行为StackPanel 的子元素,StackPanel 的第5个子对象是一个OK Button.
Windowwindow = null;
Using(FileStream fs = newFileStream("MyWindow.xaml"),FileMode.Open,FileAccess.Read)
{
window =(Window)XamlReader.Load(fs);
}
通过硬编码的方式获取Button按钮
StackPanel panel =(Stackpanel)window.Content;
Button okButton = (Button)panel.Children[4];//第五个子对象为Button
有了这个Button按钮我们就可以做我们想做的事了,例如:设置额外的属性,添加事件处理程序,执行一些无法用XAML完成的动作。
当然、用硬编码的索引和其他用户界面结构的代码并不能让人满意,因为稍微修改一下XAML它便无法正常工作了。相反,我们可以用比较通用方式编写一些代码来找到那个内容为OK字符串的Button按钮,但是对于如此简单的任务来说,这样做就有些得不偿失了。另外、如果我们想要找到包含图形元素的Button,那我们该怎么办呢!?
幸运的是,XAML中支持元素命名,这样我们就可以在过程式的代码中轻松的找到他们、并使用他们了。
命名XAML元素
在XAML语言的命名空间中有一个Name关键字,它是用来给元素命名的,如果是一个嵌入到窗体中的简单的OK按钮,其中的Name关键字可以这样使用。
<Button x:Name = "OKButton">OK</Button>
有了上述的元素命名之后,我们就可以利用Window的FindName方法(递归)的寻找到元素名称为okButton的元素了。
Window window = null;
Using(FileStream fs = newFileStream("MyWindow.xaml"),FileMode.Open,FileAccess.Read)
{
window =(Window)XamlReader.Load(fs);
}
Button okButton = (Button)window.FindName("okButton");
FindName 不仅仅是在Window中有,而且在FrameworkElement、FrameworkContentElement及许多重要的WPF类的基类中都有FindName方法的定义。
不用x:Name 也能命名元素
用x:Name 可以命名元素,但是一些类中可以定义自己的属性用来作为元素的名称(这需通过添加System.Windows.Markup.RuntimeNamePropertyAttribute特性来实现)。
例如:在FrameworkElement 和 FrameworkContenElement 因为他们有一个Name 属性,所以他们的声明中加入了一个RuntimeNamepropertyAttribute("Name")语句。这样也就意味着:只用一个字符串我们就可以设置Name属性了,而不需要再用x:Name语法了。可以使用其中的任何一中机制,但是不能同时使用他们,
2.8.2 编译XMAL
XAML编译编译包括三项事情:(1)将XAML转换成一种特殊的二进制格式,(2)将转换好的内容做为二进制资源嵌入到正在被创建的程序集中,(3)执行链接操作,将XAML与过程式代码自动连接起来。
如果想要编译一个XAML文件,我们需要做的第一个工作就是为XAML文件的根元素指定一个子类,可以使用XAML命名空间的Class 关键字来完成,例如:
<Window xmlns = "http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x = "http://schemas.microsoft.com/winfx/2006/xaml"
x:Class ="MyNameSpace.MyWindow">
//其他
</Window>
在一个独立的源文件中,但是在同一个项目中,可以添加一个子类,可以添加任何你想添加的成员,例如
Namespace MyNameSpace
{
pritial ClassMyWindow:Window
{
public MyWindow()
{
//一定要调用的,只有调用了之后才可以加载XAML中的内容
InitializeCompenent();
}
Any Other members can gohere
}
}
通常我们叫上述的代码文件叫做代码隐藏文件,如果你引用XAML中的任何一个事件处理程序,(通过事件特性、例如Button的Click特性,在代码隐藏文件里就是定义事件处理程序的地方。
(1)生成的源代码
【提示】x:Class 只能在要编译的XAML文件中使用,但是在没有x:Class的情况下 XAML文件也是可以被编译的,只是没有x:Class代表着它没有对应的代码隐藏文件而已。
还有注意:不要忘记在隐藏代码文件的构造函数中调用 InitializeCompenent();