WPF程序设计指南:XAML
1. ML是XAML的一个应用。
-
例1:一个合法片段,展现了控件以及element的嵌套层次结构:
<StackPanel><Button Foreground="LightSeaGreen" FontSize="24pt"> //指定attributeHello, XAML! //指定property(content)</Button><Ellipse Fill="Brown" Width="200" Height="100" /> //没有property<Button><Image Source="http://www.charlespetzold.com/PetzoldTattoo.jpg" Stretch="None" /></Button></StackPanel>
- 指定WPF程序所需的命名空间,我们利用“xmlns”这个attribute来声明默认的XML命名空间。此命名空间会被应用于声明出现的element以及其下的每个孩子
WPF命名空间指定方法: xmlns=http://schemas.microsoft.com/winfx/2006/xaml/presentation
例2:一个完整的XMAL文件内容:
<Button xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" // 指定WPF命名空间Foreground="LightSeaGreen" FontSize="24pt">Hello, XAML!</Button>
2. 关于root element
-
XML 文件只能有一个root element, 它可以是继承自FrameworkElement的任何类,但是不能是Window
3. 如何在c#代码中解析XAML
- WPF程序使用XamlReader.Load将一段XAML转成一个对象,如果此XAML的根element具有子element,这些element会一并被转换,并放到visual tree中。
但是,XamlReader.Load 不能直接接受字符串作为参数,只能接收Stream,或者一个XmlReader对象。
例3:将XAML定义为字符串并解析
代码
using System;
using System.IO;
using System.Windows;
using System.Windows.Markup;
using System.Xml;
namespace Petzold.LoadEmbeddedXaml
{
public class LoadEmbeddedXaml : Window
{
[STAThread]
public static void Main()
{
Application app = new Application();
app.Run(new LoadEmbeddedXaml());
}
public LoadEmbeddedXaml()
{
Title = "Load Embedded Xaml";
string strXaml =
"<Button xmlns='http://schemas.microsoft.com/" +
"winfx/2006/xaml/presentation'" +
" Foreground='LightSeaGreen' FontSize='24pt'>" +
" Click me!" +
"</Button>";
StringReader strreader = new StringReader(strXaml);
XmlTextReader xmlreader = new XmlTextReader(strreader);
object obj = XamlReader.Load(xmlreader);
Content = obj;
}
}
}
如果需要获取此button并为其增加事件处理函数,可以如下处理:
Button btn = (Button) XamlReader.Load(xmlReader);
btn.Click+=ButtonClick;
- 如果需要将XAML文件作为资源加载,需要将该XAML文件的Build Action设置为:Resource
例4:在c#文件中加载并解析XAML文件。
首先,在project中“Add New Item”,加入一个如下XML文件,命名为:LoadXamlResource
<StackPanel xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<Button Name="MyButton"
HorizontalAlignment="Center"
Margin="24">
Hello, XAML!
</Button>
<Ellipse Width="200"
Height="100"
Margin="24"
Stroke="Red"
StrokeThickness="10" />
<ListBox Width="100"
Height="100"
Margin="24">
<ListBoxItem>Sunday</ListBoxItem>
<ListBoxItem>Monday</ListBoxItem>
<ListBoxItem>Tuesday</ListBoxItem>
<ListBoxItem>Wednesday</ListBoxItem>
<ListBoxItem>Thursday</ListBoxItem>
<ListBoxItem>Friday</ListBoxItem>
<ListBoxItem>Saturday</ListBoxItem>
</ListBox>
</StackPanel>
右击该文件,选择Property,确定Build Action为 Resource
在.cs文件中输入如下内容:
using System;
using System.IO;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Markup;
namespace Petzold.LoadXamlResource
{
public class LoadXamlResource : Window
{
[STAThread]
public static void Main()
{
Application app = new Application();
app.Run(new LoadXamlResource());
}
public LoadXamlResource()
{
Title = "Load Xaml Resource";
Uri uri = new Uri("pack://application:,,,/LoadXamlResource.xml");
Stream stream = Application.GetResourceStream(uri).Stream;
FrameworkElement el = XamlReader.Load(stream) as FrameworkElement;
Content = el;
Button btn = el.FindName("MyButton") as Button;
if (btn != null)
btn.Click += ButtonOnClick;
}
void ButtonOnClick(object sender, RoutedEventArgs args)
{
MessageBox.Show("The button labeled '" +
(args.Source as Button).Content +
"' has been clicked");
}
}
}
代码分析:
首先通过静态属性Application.GetResourceStream获取一个StreamResourceInfo对象,该对象包含一个Stream属性,便得到了XML资源。
然后通过XamlReader.Load将资源转换成对象,再设为Window的Content, 变成窗口视觉树的一部分
最后通过FindName方法在书中找出特定名称的element,也就是Button, 并添加相应的事件处理函数。
- 例5:一个通过对话框加载XAML的程序实例
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Markup;
using System.Xml;
using Microsoft.Win32;
namespace Petzold.LoadXamlFile
{
public class LoadXamlFile : Window
{
Frame frame;
[STAThread]
public static void Main()
{
Application app = new Application();
app.Run(new LoadXamlFile());
}
public LoadXamlFile()
{
Title = "Load XAML File";
DockPanel dock = new DockPanel();
Content = dock;
// Create button for Open File dialog.
Button btn = new Button();
btn.Content = "Open File...";
btn.Margin = new Thickness(12);
btn.HorizontalAlignment = HorizontalAlignment.Left;
btn.Click += ButtonOnClick;
dock.Children.Add(btn);
DockPanel.SetDock(btn, Dock.Top);
// Create Frame for hosting loaded XAML.
frame = new Frame();
dock.Children.Add(frame);
}
void ButtonOnClick(object sender, RoutedEventArgs args)
{
OpenFileDialog dlg = new OpenFileDialog();
dlg.Filter = "XAML Files (*.xaml)|*.xaml|All files (*.*)|*.*";
if ((bool)dlg.ShowDialog())
{
try
{
// Read file with XmlTextReader.
XmlTextReader xmlreader = new XmlTextReader(dlg.FileName);
// Convert XAML to object.
object obj = XamlReader.Load(xmlreader);
// If it's a Window, call Show.
if (obj is Window)
{
Window win = obj as Window;
win.Owner = this;
win.Show();
}
// Otherwise, set as Content of Frame.
else
frame.Content = obj;
}
catch (Exception exc)
{
MessageBox.Show(exc.Message, Title);
}
}
}
}
}
4. XAML文件和code behind文件
- XAML文件中,WPF命名空间和XAML命名空间
一般,我们会指定WPF element的命名空间为默认的命名空间:
xmlns=http://schemas.microsoft.com/winfx/2006/xaml/presentation
WPF只是XAML的一种可能的应用方式,如果要使用XAML专用的element和attribute,需要第二个命名空间的声明:
xmlns:x=http://schemas.microsoft.com/winfx/2006/xaml
如果需要自定义class,需要添加如下的命名空间:
- 为支持定义在XAML文件中的控件和element,会需要一个code behind的c#文件:
public namespace MyNamespace
{
public partial class MyClassName: Window
{
...
}
}
partial关键字意味着该文件只是此class的一部分,在其他地方还有代码。