.Net Core WPF之XAML概述
原文链接,机器翻译,有误处参看原文。
XAML overview in WPF
2019/08/08
XAML root elements and XAML namespaces
Custom prefixes and custom types in XAML
Attached properties and attached events
This article describes the features of the XAML language and demonstrates how you can use XAML to write Windows Presentation Foundation (WPF) apps. This article specifically describes XAML as implemented by WPF. XAML itself is a larger language concept than WPF.
本文介绍了 XAML 语言的功能,并演示如何使用 XAML 编写 Windows 演示文稿基础 (WPF) 应用。本文专门介绍了由 WPF 实现的 XAML。XAML 本身是一个比 WPF 更大的语言概念。
重要
The Desktop Guide documentation is under construction.
桌面指南文档正在建设中。
What is XAML
什么是 XAML
XAML is a declarative markup language. As applied to the .NET Core programming model, XAML simplifies creating a UI for a .NET Core app. You can create visible UI elements in the declarative XAML markup, and then separate the UI definition from the run-time logic by using code-behind files that are joined to the markup through partial class definitions. XAML directly represents the instantiation of objects in a specific set of backing types defined in assemblies. This is unlike most other markup languages, which are typically an interpreted language without such a direct tie to a backing type system. XAML enables a workflow where separate parties can work on the UI and the logic of an app, using potentially different tools.
XAML 是一种声明性标记语言。与应用于 .NET 核心编程模型一样,XAML 简化了为 .NET Core 应用创建 UI 的简化。您可以在声明性 XAML 标记中创建可见的 UI 元素,然后通过使用通过部分类定义加入到标记的代码后文件将 UI 定义与运行时逻辑分开。XAML 直接表示在程序集中定义的一组特定支持类型中对象的实例化。这与大多数其他标记语言不同,后者通常是一种解释性语言,与支持类型系统没有直接关联。XAML 支持一个工作流,其中单独的各方可以使用可能不同的工具处理 UI 和应用的逻辑。
When represented as text, XAML files are XML files that generally have the .xaml extension. The files can be encoded by any XML encoding, but encoding as UTF-8 is typical.
当表示为文本时,XAML 文件是通常具有 .xaml 扩展名的 XML 文件。这些文件可以通过任何XML encoding进行编码,一般使用UTF-8编码。
The following example shows how you might create a button as part of a UI. This example is intended to give you a flavor of how XAML represents common UI programming metaphors (it is not a complete sample).
下面的示例演示了,如何创建按钮作为 UI 的一部分。此示例旨在让您了解 XAML 如何表示常见的 UI 编程隐喻(它不是一个完整的示例)。
1 <StackPanel> 2 <Button Content="Click Me"/> 3 </StackPanel>
XAML syntax in brief
XAML 语法简述
The following sections explain the basic forms of XAML syntax, and give a short markup example. These sections are not intended to provide complete information about each syntax form, such as how these are represented in the backing type system.
以下各节将解释 XAML 语法的基本形式,并给出一个简短的标记示例。这些部分不旨在提供有关每个语法窗体的完整信息,例如这些语法形式在支持类型系统中的表示方式。
Much of the material in the next few sections will be elementary to you if you have previous familiarity with the XML language. This is a consequence of one of the basic design principles of XAML. The XAML language defines concepts of its own, but these concepts work within the XML language and markup form.
如果您以前熟悉 XML 语言,则下面几节中的大部分材料将是基本材料。这是 XAML 基本设计原则之一的结果。XAML 语言定义了它自己的概念,但这些概念在 XML 语言和标记形式中工作。
XAML object elements
XAML 对象元素
An object element typically declares an instance of a type. That type is defined in the assemblies referenced by the technology that uses XAML as a language.
对象元素通常声明类型的实例。该类型在使用 XAML 作为语言的技术引用的程序集中定义。
Object element syntax always starts with an opening angle bracket (<). This is followed by the name of the type where you want to create an instance. (The name can include a prefix, a concept that will be explained later.) After this, you can optionally declare attributes on the object element. To complete the object element tag, end with a closing angle bracket (>). You can instead use a self-closing form that does not have any content, by completing the tag with a forward slash and closing angle bracket in succession (/>). For example, look at the previously shown markup snippet again.
对象元素语法始终以左括号 (< ) 开头。后面是要在其中创建实例的类型的名称。(名称可以包含前缀,稍后将解释这一概念。在此之后,您可以选择声明对象元素上的属性。要完成对象元素标记,以右尖括号 (>) 结尾。相反,您可以使用没有任何内容的自结束窗体,通过连续使用前斜杠和右尖括号完成标记(/>)。例如,再次查看之前显示的标记代码段。
1 <StackPanel> 2 <Button Content="Click Me"/> 3 </StackPanel>
This specifies two object elements: <StackPanel> (with content, and a closing tag later), and <Button .../> (the self-closing form, with several attributes). The object elements StackPanel and Button each map to the name of a class that is defined by WPF and is part of the WPF assemblies. When you specify an object element tag, you create an instruction for XAML processing to create a new instance of the underlying type. Each instance is created by calling the parameterless constructor of the underlying type when parsing and loading the XAML.
这指定了两个对象元素:<StackPanel>(包含内容,稍后有结束标记),<Button .../>(具有多个属性的自闭形式)。对象元素 StackPanel 和 Button 每个映射到由 WPF 定义的类的名称,该类是 WPF 程序集的一部分。指定对象元素标记时,将创建 XAML 处理指令以创建基础类型的新实例。在分析和加载 XAML 时,通过调用基础类型的无参数构造函数来创建每个实例。
Attribute syntax (properties)
属性语法(属性)
Properties of an object can often be expressed as attributes of the object element. The attribute syntax names the object property that is being set, followed by the assignment operator (=). The value of an attribute is always specified as a string that is contained within quotation marks.
对象的属性通常可以表示为对象元素的属性。属性语法为正在设置的对象属性命名,后跟赋值运算符 (=)。属性的值始终指定为包含在引号中的字符串。
Attribute syntax is the most streamlined property setting syntax and is the most intuitive syntax to use for developers who have used markup languages in the past. For example, the following markup creates a button that has red text and a blue background in addition to display text specified as Content.
属性语法是最简化的属性设置语法,是过去使用标记语言的开发人员使用的最直观的语法。例如,以下标记除了显示指定为"内容"的文本外,还创建一个包含红色文本和蓝色背景的按钮。
1 <Button Background="Blue" Foreground="Red" Content="This is a button"/>
Property element syntax
属性元素语法
For some properties of an object element, attribute syntax is not possible, because the object or information necessary to provide the property value cannot be adequately expressed within the quotation mark and string restrictions of attribute syntax. For these cases, a different syntax known as property element syntax can be used.
对于对象元素的某些属性,属性语法是不可能的,因为提供属性值所需的对象或信息不能在属性语法的引号和字符串限制中充分表示。在这些情况下,可以使用称为属性元素语法的不同语法。
The syntax for the property element start tag is <TypeName.PropertyName>. Generally, the content of that tag is an object element of the type that the property takes as its value. After specifying the content, you must close the property element with an end tag. The syntax for the end tag is </TypeName.PropertyName>.
属性元素开始标记的语法为 <TypeName.PropertyName>。通常,该标记的内容是属性作为其值的类型的对象元素。指定内容后,必须使用结束标记关闭属性元素。结束标记的语法为 </TypeName.PropertyName> 。
If an attribute syntax is possible, using the attribute syntax is typically more convenient and enables a more compact markup, but that is often just a matter of style, not a technical limitation. The following example shows the same properties being set as in the previous attribute syntax example, but this time by using property element syntax for all properties of the Button.
如果属性语法是可能的,则使用属性语法通常更方便,并且启用更紧凑的标记,但这通常只是样式问题,而不是技术限制。下面的示例显示与上一个属性语法示例中设置的属性相同,但这次对 Button 的所有属性使用属性元素语法。
1 <Button> 2 <Button.Background> 3 <SolidColorBrush Color="Blue"/> 4 </Button.Background> 5 <Button.Foreground> 6 <SolidColorBrush Color="Red"/> 7 </Button.Foreground> 8 <Button.Content> 9 This is a button 10 </Button.Content> 11 </Button>
Collection syntax
集合语法
The XAML language includes some optimizations that produce more human-readable markup. One such optimization is that if a particular property takes a collection type, then items that you declare in markup as child elements within that property's value become part of the collection. In this case a collection of child object elements is the value being set to the collection property.
XAML 语言包括一些优化,这些优化可生成更多人类可读的标记。其中一种优化是,如果特定属性采用集合类型,则在标记中声明为该属性值中的子元素的项将成为集合的一部分。在这种情况下,子对象元素的集合是设置为集合属性的值。
The following example shows collection syntax for setting values of the GradientStops property.
下面的示例显示了用于设置GradientStop属性的值的集合语法。
1 <LinearGradientBrush> 2 <LinearGradientBrush.GradientStops> 3 <!-- no explicit new GradientStopCollection, parser knows how to find or create --> 4 <GradientStop Offset="0.0" Color="Red" /> 5 <GradientStop Offset="1.0" Color="Blue" /> 6 </LinearGradientBrush.GradientStops> 7 </LinearGradientBrush>
XAML content properties
XAML 内容属性
XAML specifies a language feature whereby a class can designate exactly one of its properties to be the XAML content property. Child elements of that object element are used to set the value of that content property. In other words, for the content property uniquely, you can omit a property element when setting that property in XAML markup and produce a more visible parent/child metaphor in the markup.
XAML 指定一种语言功能,根据该功能,类可以将其属性之一精确指定为 XAML 内容属性。该对象元素的子元素用于设置该内容属性的值。换句话说,对于内容属性,可以在 XAML 标记中设置该属性时省略属性元素,并在标记中生成更明显的父/子隐喻。
For example, Border specifies a content property of Child. The following two Border elements are treated identically. The first one takes advantage of the content property syntax and omits the Border.Child property element. The second one shows Border.Child explicitly.
例如,Border指定Child的内容属性。以下两个Border元素的处理方式相同。第一个利用内容属性语法并省略了 Border.child 属性元素。第二个显式显示 Border.child。
1 <Border> 2 <TextBox Width="300"/> 3 </Border> 4 <!--explicit equivalent--> 5 <Border> 6 <Border.Child> 7 <TextBox Width="300"/> 8 </Border.Child> 9 </Border>
As a rule of the XAML language, the value of a XAML content property must be given either entirely before or entirely after any other property elements on that object element. For instance, the following markup does not compile.
作为 XAML 语言的规则,XAML 内容属性的值必须完全在该对象元素上的任何其他属性元素之前或完全给定之后。例如,以下标记不编译。
1 <Button>I am a 2 <Button.Background>Blue</Button.Background> 3 blue button</Button>
Text content
文本内容
A small number of XAML elements can directly process text as their content. To enable this, one of the following cases must be true:
少数 XAML 元素可以直接将文本作为其内容处理。要启用此功能,以下情况之一必须为 true:
The class must declare a content property, and that content property must be of a type assignable to a string (the type could be Object). For instance, any ContentControl uses Content as its content property and it is type Object, and this supports the following usage on a ContentControl such as a Button: <Button>Hello</Button>.
类必须声明内容属性,并且该内容属性必须是可分配给字符串的类型(该类型可以是Object)。例如,任何 ContentControl 都使用Content作为其内容属性,并且它的类型为"Object",这支持ContentControl的以下用法,例如Button:<Button>Hello</Button>。
The type must declare a type converter, in which case the text content is used as initialization text for that type converter. For example, <Brush>Blue</Brush> converts the content value of Blue into a brush. This case is less common in practice.
类型必须声明类型转换器,在这种情况下,文本内容用作该类型转换器的初始化文本。例如,<Brush>Blue</Brush> 将蓝色的内容值转换为画笔。这种情况在实践中并不常见。
The type must be a known XAML language primitive.
类型必须是已知的 XAML 语言基元。
Content properties and collection syntax combined
内容属性和集合语法组合
Consider this example.
请考虑此示例。
1 <StackPanel> 2 <Button>First Button</Button> 3 <Button>Second Button</Button> 4 </StackPanel>
Here, each Button is a child element of StackPanel. This is a streamlined and intuitive markup that omits two tags for two different reasons.
在这里,每个Button是StackPanel的子元素。这是一个简化和直观的标记,由于两个不同的原因省略了两个标记。
Omitted StackPanel.Children property element: StackPanel derives from Panel. Panel defines Panel.Children as its XAML content property.
省略的堆栈面板.子级属性元素:StackPanel派生自Panel。Panel将 Panel.Children定义为其 XAML 内容属性。
Omitted UIElementCollection object element: The Panel.Children property takes the type UIElementCollection, which implements IList. The collection's element tag can be omitted, based on the XAML rules for processing collections such as IList. (In this case, UIElementCollection actually cannot be instantiated because it does not expose a parameterless constructor, and that is why the UIElementCollection object element is shown commented out).
省略的 UIElementCollection 对象元素:Panel.Children属性采用实现 IList的UIElementCollection类型。可以根据用于处理集合(如 IList )的 XAML 规则省略集合的元素标记。(在这种情况下,实际上,不能实例化UIElementCollection,因为它不公开无参数构造函数,这就是为什么 UIElementCollection 对象元素被注释掉的原因。
1 <StackPanel> 2 <StackPanel.Children> 3 <!--<UIElementCollection>--> 4 <Button>First Button</Button> 5 <Button>Second Button</Button> 6 <!--</UIElementCollection>--> 7 </StackPanel.Children> 8 </StackPanel>
Attribute syntax (events)
属性语法(事件)
Attribute syntax can also be used for members that are events rather than properties. In this case, the attribute's name is the name of the event. In the WPF implementation of events for XAML, the attribute's value is the name of a handler that implements that event's delegate. For example, the following markup assigns a handler for the Click event to a Button created in markup:
属性语法也可用于事件而不是属性的成员。在这种情况下,属性的名称是事件的名称。在 XAML 事件的 WPF 实现中,属性的值是实现该事件的委托的处理程序的名称。例如,以下标记将Click事件的处理程序分配给在标记中创建的Button:
1 <Page 2 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 3 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 4 x:Class="ExampleNamespace.ExamplePage"> 5 <Button Click="Button_Click" >Click Me!</Button> 6 </Page>
There is more to events and XAML in WPF than just this example of the attribute syntax. For example, you might wonder what the ClickHandler referenced here represents and how it is defined. This will be explained in the upcoming Events and XAML code-behind section of this article.
WPF 中的事件和 XAML 不仅仅是属性语法的此示例。例如,您可能想知道此处引用的 ClickHandler 表示什么以及如何定义它。本文即将推出的"事件"和"XAML 代码落后"部分将对此进行说明。
Case and white space in XAML
XAML 中的外壳和空白
In general, XAML is case-sensitive. For purposes of resolving backing types, WPF XAML is case-sensitive by the same rules that the CLR is case-sensitive. Object elements, property elements, and attribute names must all be specified by using the sensitive casing when compared by name to the underlying type in the assembly, or to a member of a type. XAML language keywords and primitives are also case-sensitive. Values are not always case-sensitive. Case sensitivity for values will depend on the type converter behavior associated with the property that takes the value, or the property value type. For example, properties that take the Boolean type can take either true or True as equivalent values, but only because the native WPF XAML parser type conversion for string to Boolean already permits these as equivalents.
通常,XAML 区分大小写。为了解析后备类型,WPF XAML 与 CLR 区分大小写的规则一样区分大小写。当按名称与程序集中的基础类型或类型的成员进行比较时,必须使用敏感大小写来指定对象元素、属性元素和属性名称。XAML 语言关键字和基元也区分大小写。值并不总是区分大小写。值的区分大小写将取决于与获取值的属性或属性值类型关联的类型转换器行为。例如,采用Boolean类型的属性可以将 true 或 True 作为等效值,但仅因为字符串到Boolean的本机 WPF XAML 解析器类型转换已允许这些作为等效值。
WPF XAML processors and serializers will ignore or drop all nonsignificant white space, and will normalize any significant white space. This is consistent with the default white-space behavior recommendations of the XAML specification. This behavior is only of consequence when you specify strings within XAML content properties. In simplest terms, XAML converts space, linefeed, and tab characters into spaces, and then preserves one space if found at either end of a contiguous string. The full explanation of XAML white-space handling is not covered in this article.
WPF XAML 处理器和序列化程序将忽略或丢弃所有不重要的空白,并将任何重要的空白点化。这与 XAML 规范的默认空白行为建议一致。仅当在 XAML 内容属性中指定字符串时,此行为才具有后果性。在最简单术语中,XAML 将空格、换行符和制表符转换为空格,然后在连续字符串的任意一端找到一个空格。本文未介绍 XAML 空白处理的完整说明。
Markup extensions
标记扩展
Markup extensions are a XAML language concept. When used to provide the value of an attribute syntax, curly braces ({ and }) indicate a markup extension usage. This usage directs the XAML processing to escape from the general treatment of attribute values as either a literal string or a string-convertible value.
标记扩展是一个 XAML 语言概念。当用于提供属性语法的值时,大括号({ and })表示标记扩展用法。此用法指示 XAML 处理从属性值作为文本字符串或字符串可转换值的一般处理中转义。
The most common markup extensions used in WPF app programming are Binding, used for data binding expressions, and the resource references StaticResource and DynamicResource. By using markup extensions, you can use attribute syntax to provide values for properties even if that property does not support an attribute syntax in general. Markup extensions often use intermediate expression types to enable features such as deferring values or referencing other objects that are only present at run-time.
WPF应用编程中使用的最常见的标记扩展是绑定,用于数据绑定表达式,资源引用静态资源和动态资源。通过使用标记扩展,可以使用属性语法为属性提供值,即使该属性通常不支持属性语法也是如此。标记扩展通常使用中间表达式类型来启用功能,例如延迟值或引用仅在运行时存在的其他对象。
For example, the following markup sets the value of the Style property using attribute syntax. The Style property takes an instance of the Style class, which by default could not be instantiated by an attribute syntax string. But in this case, the attribute references a particular markup extension, StaticResource. When that markup extension is processed, it returns a reference to a style that was previously instantiated as a keyed resource in a resource dictionary.
例如,下面的标记使用属性语法设置了Style 属性的值。Style属性采用Style类的实例,默认情况下,属性语法字符串无法直接进行实例化。但在该例中,该属性引用一个特别的标记扩展名------"StaticResource"。处理该标记扩展时,将返回一个指向style的引用,该style在资源字典(resource dictionary)中提前实例化成一个键值资源。
1 <Page.Resources> 2 <SolidColorBrush x:Key="MyBrush" Color="Gold"/> 3 <Style TargetType="Border" x:Key="PageBackground"> 4 <Setter Property="Background" Value="Blue"/> 5 </Style> 6 </Page.Resources> 7 <StackPanel> 8 <Border Style="{StaticResource PageBackground}"> 9 </Border> 10 </StackPanel>
Type converters
类型转换器
In the XAML Syntax in Brief section, it was stated that the attribute value must be able to be set by a string. The basic, native handling of how strings are converted into other object types or primitive values is based on the String type itself, in addition to native processing for certain types such as DateTime or Uri. But many WPF types or members of those types extend the basic string attribute processing behavior in such a way that instances of more complex object types can be specified as strings and attributes.
在XAML 语法简介部分中,指出属性值必须能够由字符串设置。除了某些类型(如DateTime 或 Uri)的本机处理外,字符串如何转换为其他对象类型或基元值的基本本机处理基于String类型本身。但是,许多 WPF 类型或这些类型的成员扩展了基本字符串属性处理行为,以便可以将更复杂的对象类型的实例指定为字符串和属性。
The Thickness structure is an example of a type that has a type conversion enabled for XAML usages. Thickness indicates measurements within a nested rectangle and is used as the value for properties such as Margin. By placing a type converter on Thickness, all properties that use a Thickness are easier to specify in XAML because they can be specified as attributes. The following example uses a type conversion and attribute syntax to provide a value for a Margin:
"厚度"结构是为 XAML 用法启用类型转换的类型的示例。厚度表示嵌套矩形内的度量值,并用作属性(如边距)的值。通过将类型转换器放在"厚度"上,使用"厚度"的所有属性都更容易在 XAML 中指定,因为它们可以指定为属性。下面的示例使用类型转换和属性语法为边距提供值:
1 <Button Margin="10,20,10,30" Content="Click me"/>
The previous attribute syntax example is equivalent to the following more verbose syntax example, where the Margin is instead set through property element syntax containing a Thickness object element. The four key properties of Thickness are set as attributes on the new instance:
前面的属性语法示例等效于以下更详细的语法示例,其中边距通过包含Thickness对象元素的属性元素语法进行设置。"厚度"的四个关键属性在新实例上设置为属性:
1 <Button Content="Click me"> 2 <Button.Margin> 3 <Thickness Left="10" Top="20" Right="10" Bottom="30"/> 4 </Button.Margin> 5 </Button>
备注
There are also a limited number of objects where the type conversion is the only public way to set a property to that type without involving a subclass, because the type itself does not have a parameterless constructor. An example is Cursor.
还有数量有限的对象,其中类型转换是将属性设置为该类型而不涉及子类的唯一公共方法,因为类型本身没有无参数构造函数。例如光标。
XAML root elements and XAML namespaces
XAML 根元素和 XAML 命名空间
A XAML file must have only one root element, in order to be both a well-formed XML file and a valid XAML file. For typical WPF scenarios, you use a root element that has a prominent meaning in the WPF app model (for example, Window or Page for a page, ResourceDictionary for an external dictionary, or Application for the app definition). The following example shows the root element of a typical XAML file for a WPF page, with the root element of Page.
XAML 文件必须只有一个根元素,才能同时成为格式良好的 XML 文件和有效的 XAML 文件。对于典型的 WPF 方案,使用在 WPF 应用模型中具有突出含义的根元素(例如,页面的窗口或页面、外部字典的"资源字典"或应用程序定义的应用程序)。下面的示例显示了 WPF 页的典型 XAML 文件的根元素,该根元素具有 Page的根元素。
1 <Page 2 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 3 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"> 4 </Page>
The root element also contains the attributes xmlns and xmlns:x. These attributes indicate to a XAML processor which XAML namespaces contain the type definitions for backing types that the markup will reference as elements. The xmlns attribute specifically indicates the default XAML namespace. Within the default XAML namespace, object elements in the markup can be specified without a prefix. For most WPF app scenarios, and for almost all of the examples given in the WPF sections of the SDK, the default XAML namespace is mapped to the WPF namespace http://schemas.microsoft.com/winfx/2006/xaml/presentation. The xmlns:x attribute indicates an additional XAML namespace, which maps the XAML language namespace http://schemas.microsoft.com/winfx/2006/xaml.
根元素还包含属性 xmlns 和 xmlns:x。 这些属性指示 XAML 处理器,其中 XAML 命名空间包含标记将作为元素引用的后备类型的类型定义。xmlns 属性专门指示默认的 XAML 命名空间。在默认的 XAML 命名空间中,可以在没有前缀的情况下指定标记中的对象元素。对于大多数 WPF 应用方案,以及 SDK 的 WPF 部分中给出的几乎所有示例,默认 XAML 命名空间映射到 WPF 命名空间http://schemas.microsoft.com/winfx/2006/xaml/presentation。xmlns:x 属性指示一个附加的 XAML 命名空间,该命名空间映射 xAML 语言命名空间http://schemas.microsoft.com/winfx/2006/xaml。
This usage of xmlns to define a scope for usage and mapping of a namescope is consistent with the XML 1.0 specification. XAML namescopes are different from XML namescopes only in that a XAML namescope also implies something about how the namescope's elements are backed by types when it comes to type resolution and parsing the XAML.
xml 的这种用法用于定义名称范围的使用范围和映射,这与 XML 1.0 规范是一致的。XAML 名称范围与 XML 名称范围不同,只是因为 XAML 名称范围还暗示了在类型解析和分析 XAML 时名称范围的元素如何由类型支持。
The xmlns attributes are only strictly necessary on the root element of each XAML file. xmlns definitions will apply to all descendant elements of the root element (this behavior is again consistent with the XML 1.0 specification for xmlns.) xmlns attributes are also permitted on other elements underneath the root, and would apply to any descendant elements of the defining element. However, frequent definition or redefinition of XAML namespaces can result in a XAML markup style that is difficult to read.
xmlns 属性仅在每个 XAML 文件的根元素上严格必要。xmlns 定义将应用于根元素的所有后代元素(此行为再次与 xmlns 的 XML 1.0 规范一致)xmlns 属性也允许在根目录下的其他元素上,并将应用于任何子体元素的元素。但是,频繁定义或重新定义 XAML 命名空间可能会导致难以读取的 XAML 标记样式。
The WPF implementation of its XAML processor includes an infrastructure that has awareness of the WPF core assemblies. The WPF core assemblies are known to contain the types that support the WPF mappings to the default XAML namespace. This is enabled through configuration that is part of your project build file and the WPF build and project systems. Therefore, declaring the default XAML namespace as the default xmlns is all that is necessary in order to reference XAML elements that come from WPF assemblies.
其 XAML 处理器的 WPF 实现包括具有 WPF 核心程序集感知的基础结构。众所周知,WPF 核心程序集包含支持 WPF 映射到默认 XAML 命名空间的类型。这是通过作为项目生成文件以及 WPF 生成和项目系统的一部分的配置启用的。因此,将默认 XAML 命名空间声明为默认 xmlns 是引用来自 WPF 程序集的 XAML 元素所必需的。
The x: prefix
x:前缀
In the previous root element example, the prefix x: was used to map the XAML namespace http://schemas.microsoft.com/winfx/2006/xaml, which is the dedicated XAML namespace that supports XAML language constructs. This x: prefix is used for mapping this XAML namespace in the templates for projects, in examples, and in documentation throughout this SDK. The XAML namespace for the XAML language contains several programming constructs that you will use frequently in your XAML. The following is a listing of the most common x: prefix programming constructs you will use:
在前面的根元素示例中,前缀 x:用于映射 xAML 命名空间http://schemas.microsoft.com/winfx/2006/xaml,它是支持 XAML 语言构造的专用 XAML 命名空间。此 x:前缀用于映射整个 SDK 中的项目模板、示例和文档中的此 XAML 命名空间。XAML 语言的 XAML 命名空间包含多个将在 XAML 中经常使用的编程构造。以下是最常用的 x: 前缀编程构造的列表,
- x:Key: Sets a unique key for each resource in a ResourceDictionary (or similar dictionary concepts in other frameworks). x:Key will probably account for 90 percent of the x: usages you will see in a typical WPF app's markup.
- x:Key:为资源字典(或其他框架中的类似字典概念)中的每个资源设置唯一键。
- x:Class: Specifies the CLR namespace and class name for the class that provides code-behind for a XAML page. You must have such a class to support code-behind per the WPF programming model, and therefore you almost always see x: mapped, even if there are no resources.
- x:Class:为为 XAML 页提供代码落后的类指定 CLR 命名空间和类名称。您必须有这样一个类来支持 WPF 编程模型的代码落后,因此,即使没有资源,您几乎总是会看到 x:映射。
- x:Name: Specifies a run-time object name for the instance that exists in run-time code after an object element is processed. In general, you will frequently use a WPF-defined equivalent property for x:Name. Such properties map specifically to a CLR backing property and are thus more convenient for app programming, where you frequently use run-time code to find the named elements from initialized XAML. The most common such property is FrameworkElement.Name. You might still use x:Name when the equivalent WPF framework-level Name property is not supported in a particular type. This occurs in certain animation scenarios.
- x:Name:为处理对象元素后运行时代码中存在的实例指定运行时对象名称。通常,您将经常使用 WPF 定义的等效属性来表示 x:Name。此类属性专门映射到 CLR 支持属性,因此更便于应用编程,在应用编程中,经常使用运行时代码从初始化的 XAML 中查找命名元素。最常见的此类属性是FrameworkElement.Name。当特定类型不支持等效的 WPF 框架级别 Name属性时,您可能仍使用x:Name。 这在某些动画方案中发生。
- x:Static: Enables a reference that returns a static value that is not otherwise a XAML-compatible property.
- x:Static:启用返回的静态值的引用,该值不是 XAML 兼容的属性。
- x:Type: Constructs a Type reference based on a type name. This is used to specify attributes that take Type, such as Style.TargetType, although frequently the property has native string-to-Type conversion in such a way that the x:Type markup extension usage is optional.
- x:Type:基于类型名称构造类型引用。这用于指定采用 Type的属性,如 Style.TargetType,尽管该属性通常具有本机字符串到类型的转换,以便 x:Type 标记扩展用法是可选的。
There are additional programming constructs in the x: prefix/XAML namespace, which are not as common. For details, see XAML Namespace (x:) Language Features.
在 x: 前缀/XAML 命名空间中还有其他编程构造,它们并不常见。有关详细信息,请参阅XAML 命名空间 (x:)语言特征.
Custom prefixes and custom types in XAML
XAML 中的自定义前缀和自定义类型
For your own custom assemblies, or for assemblies outside the WPF core of PresentationCore, PresentationFramework and WindowsBase, you can specify the assembly as part of a custom xmlns mapping. You can then reference types from that assembly in your XAML, so long as that type is correctly implemented to support the XAML usages you are attempting.
对于您自己的自定义程序集,或者对于演示文稿核心、演示文稿框架和 WindowsBase 的 WPF 核心外的程序集,可以将程序集指定为自定义 xmlns 映射的一部分。然后,您可以在 XAML 中引用该程序集中的类型,只要该类型已正确实现以支持您尝试的 XAML 用法。
The following is a basic example of how custom prefixes work in XAML markup. The prefix custom is defined in the root element tag, and mapped to a specific assembly that is packaged and available with the app. This assembly contains a type NumericUpDown, which is implemented to support general XAML usage as well as using a class inheritance that permits its insertion at this particular point in a WPF XAML content model. An instance of this NumericUpDown control is declared as an object element, using the prefix so that a XAML parser knows which XAML namespace contains the type, and therefore where the backing assembly is that contains the type definition.
下面是自定义前缀在 XAML 标记中工作的基本示例。前缀自定义在根元素标记中定义,并映射到打包并与应用一起可用的特定程序集。此程序集包含一个类型 NumericUpDown,该类型旨在支持常规 XAML 用法,以及使用允许在此特定点插入 WPF XAML 内容模型中的类继承。此 NumericUpDown 控件的实例声明为对象元素,使用前缀使 XAML 解析器知道哪个 XAML 命名空间包含类型,因此支持程序集包含类型定义的位置。
1 <Page 2 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 3 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 4 xmlns:custom="clr-namespace:NumericUpDownCustomControl;assembly=CustomLibrary" 5 > 6 <StackPanel Name="LayoutRoot"> 7 <custom:NumericUpDown Name="numericCtrl1" Width="100" Height="60"/> 8 ... 9 </StackPanel> 10 </Page>
Events and XAML code-behind
事件和 XAML 代码背后
Most WPF apps consist of both XAML markup and code-behind. Within a project, the XAML is written as a .xaml file, and a CLR language such as Microsoft Visual Basic or C# is used to write a code-behind file. When a XAML file is markup compiled as part of the WPF programming and application models, the location of the XAML code-behind file for a XAML file is identified by specifying a namespace and class as the x:Class attribute of the root element of the XAML.
大多数 WPF 应用都由 XAML 标记和代码支持组成。在项目中,XAML 被写入 .xaml 文件,而 CLR 语言(如 Microsoft Visual Basic 或 C#)用于编写代码落后文件。当将 XAML 文件作为 WPF 编程和应用程序模型的一部分编译时,通过将命名空间和类指定为 XAML 根元素的 x:Class 属性来标识 XAML 文件的 XAML 代码落后文件的位置。
In the examples so far, you have seen several buttons, but none of these buttons had any logical behavior associated with them yet. The primary application-level mechanism for adding a behavior for an object element is to use an existing event of the element class, and to write a specific handler for that event that is invoked when that event is raised at run-time. The event name and the name of the handler to use are specified in the markup, whereas the code that implements your handler is defined in the code-behind.
到目前为止,在示例中,您已经看到多个按钮,但这些按钮中没有任何一个与它们关联的逻辑行为。为对象元素添加行为的主要应用程序级机制是使用元素类的现有事件,并为在运行时引发该事件时调用的事件编写特定的处理程序。标记中指定了要使用的事件名称和处理程序的名称,而实现处理程序的代码在代码落后中定义。
1 <Page 2 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 3 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 4 x:Class="ExampleNamespace.ExamplePage"> 5 <Button Click="Button_Click" >Click Me!</Button> 6 </Page>
1 namespace ExampleNamespace 2 { 3 public partial class ExamplePage 4 { 5 void Button_Click(object sender, RoutedEventArgs e) 6 { 7 Button b = e.Source as Button; 8 b.Foreground = Brushes.Red; 9 } 10 } 11 }
Notice that the code-behind file uses the CLR namespace ExampleNamespace and declares ExamplePage as a partial class within that namespace. This parallels the x:Class attribute value of ExampleNamespace.ExamplePage that was provided in the markup root. The WPF markup compiler will create a partial class for any compiled XAML file, by deriving a class from the root element type. When you provide code-behind that also defines the same partial class, the resulting code is combined within the same namespace and class of the compiled app.
请注意,代码落后文件使用 CLR 命名空间示例命名空间,并将 ExamplePage 声明为该命名空间中的部分类。这与示例命名空间的 x:Class 属性值类似。示例页在标记根中提供。WPF 标记编译器将通过从根元素类型派生类,为任何编译的 XAML 文件创建部分类。当您提供也定义同一部分类的代码时,生成的代码将合并在编译应用的同一命名空间和类中。
If you do not want to create a separate code-behind file, you can also inline your code in a XAML file. However, inline code is a less versatile technique that has substantial limitations.
如果不想创建单独的代码落后文件,还可以在 XAML 文件中内联代码。但是,内联代码是一种不太通用的技术,具有很大的局限性。
Routed events
路由事件
A particular event feature that is fundamental to WPF is a routed event. Routed events enable an element to handle an event that was raised by a different element, as long as the elements are connected through a tree relationship. When specifying event handling with a XAML attribute, the routed event can be listened for and handled on any element, including elements that do not list that particular event in the class members table. This is accomplished by qualifying the event name attribute with the owning class name. For instance, the parent StackPanel in the ongoing StackPanel / Button example could register a handler for the child element button's Click event by specifying the attribute Button.Click on the StackPanel object element, with your handler name as the attribute value.
WPF 的基础特定事件功能是路由事件。路由事件使元素能够处理由其他元素引发的事件,只要元素通过树关系连接。使用 XAML 属性指定事件处理时,可以在任何元素(包括不列出类成员表中的特定事件的元素)上侦听和处理路由事件。这是通过使用所属类名限定事件名称属性来实现的。例如,正在进行的 StackPanel / Button 示例中的父 StackPanel可以通过指定属性 Button来注册子元素按钮的 Click事件的处理程序。
XAML named elements
XAML 命名元素
By default, the object instance that is created in an object graph by processing a XAML object element does not possess a unique identifier or object reference. In contrast, if you call a constructor in code, you almost always use the constructor result to set a variable to the constructed instance, so that you can reference the instance later in your code. In order to provide standardized access to objects that were created through a markup definition, XAML defines the x:Name attribute. You can set the value of the x:Name attribute on any object element. In your code-behind, the identifier you choose is equivalent to an instance variable that refers to the constructed instance. In all respects, named elements function as if they were object instances (the name references that instance), and your code-behind can reference the named elements to handle run-time interactions within the app. This connection between instances and variables is accomplished by the WPF XAML markup compiler, and more specifically involve features and patterns such as InitializeComponent that will not be discussed in detail in this article.
默认情况下,通过处理 XAML 对象元素在对象图中创建的对象实例不具有唯一标识符或对象引用。相反,如果在代码中调用构造函数,则几乎总是使用构造函数结果将变量设置为构造的实例,以便稍后可以在代码中引用该实例。为了提供对通过标记定义创建的对象的标准化访问,XAML 定义了x:Name 属性。您可以在任何对象元素上设置 x:Name 属性的值。在代码落后中,您选择的标识符等效于引用构造的实例的实例变量。在所有方面,命名元素的功能就像它们是对象实例(该实例的名称引用),并且代码隐藏可以引用命名元素来处理应用中的运行时交互。实例和变量之间的这种连接由 WPF XAML 标记编译器完成,更具体地说,它涉及一些功能和模式,如初始化组件,本文将对此进行详细讨论。
WPF framework-level XAML elements inherit a Name property, which is equivalent to the XAML defined x:Name attribute. Certain other classes also provide property-level equivalents for x:Name, which is also generally defined as a Name property. Generally speaking, if you cannot find a Name property in the members table for your chosen element/type, use x:Name instead. The x:Name values will provide an identifier to a XAML element that can be used at run-time, either by specific subsystems or by utility methods such as FindName.
WPF 框架级 XAML 元素继承Name 属性,该属性等效于 XAML 定义的 x:Name 属性。某些其他类还提供 x:Name 的属性级等效项,通常也定义为 Name 属性。一般来说,如果在成员表中找不到所选元素/类型的 Name 属性,请使用 x:Name。x:Name 值将为 XAML 元素提供标识符,该元素可在运行时通过特定子系统或实用程序方法(如 FindName)使用。
The following example sets Name on a StackPanel element. Then, a handler on a Button within that StackPanel references the StackPanel through its instance reference buttonContainer as set by Name.
下面的示例在StackPanel元素上设置名称。然后,该 StackPanel 中的按钮上的处理程序通过其实例引用按钮容器引用 StackPanel,按Name设置。
1 <StackPanel Name="buttonContainer"> 2 <Button Click="RemoveThis">Click to remove this button</Button> 3 </StackPanel>
1 void RemoveThis(object sender, RoutedEventArgs e) 2 { 3 FrameworkElement fe = e.Source as FrameworkElement; 4 if (buttonContainer.Children.Contains(fe)) 5 { 6 buttonContainer.Children.Remove(fe); 7 } 8 }
Just like a variable, the XAML name for an instance is governed by a concept of scope, so that names can be enforced to be unique within a certain scope that is predictable. The primary markup that defines a page denotes one unique XAML namescope, with the XAML namescope boundary being the root element of that page. However, other markup sources can interact with a page at run-time, such as styles or templates within styles, and such markup sources often have their own XAML namescopes that do not necessarily connect with the XAML namescope of the page. For more information on x:Name and XAML namescopes, see Name, x:Name Directive.
与变量一样,实例的 XAML 名称受作用域概念的管辖,因此可以强制名称在可预测的特定范围内是唯一的。定义页面的主标记表示一个唯一的 XAML 名称范围,XAML 名称范围边界是该页的根元素。但是,其他标记源可以在运行时与页面交互,例如样式中的样式或模板,并且此类标记源通常具有自己的 XAML 名称范围,这些名称不一定与页面的 XAML 名称范围连接。有关 x:Name 和 XAML 名称范围的详细信息,请参阅名称 x:Name 指令 。
Attached properties and attached events
附加属性和附加事件
XAML specifies a language feature that enables certain properties or events to be specified on any element, regardless of whether the property or event exists in the type's definitions for the element it is being set on. The properties version of this feature is called an attached property, the events version is called an attached event. Conceptually, you can think of attached properties and attached events as global members that can be set on any XAML element/object instance. However, that element/class or a larger infrastructure must support a backing property store for the attached values.
XAML 指定一种语言功能,该功能允许在任何元素上指定某些属性或事件,而不管该属性或事件是否存在于要为其设置的元素的类型定义中。此功能的属性版本称为附加属性,事件版本称为附加事件。从概念上讲,可以将附加属性和附加事件视为可在任何 XAML 元素/对象实例上设置的全局成员。但是,该元素/类或较大的基础结构必须支持附加值的后备属性存储。
Attached properties in XAML are typically used through attribute syntax. In attribute syntax, you specify an attached property in the form ownerType.propertyName.
XAML 中的附加属性通常通过属性语法使用。在属性语法中,您可以在窗体所有者 Type.propertyName 中指定附加属性。
Superficially, this resembles a property element usage, but in this case the ownerType you specify is always a different type than the object element where the attached property is being set. ownerType is the type that provides the accessor methods that are required by a XAML processor in order to get or set the attached property value.
从表面上看,这类似于属性元素用法,但在这种情况下,您指定的所有者类型始终与正在设置附加属性的对象元素类型不同。ownerType 是提供 XAML 处理器获取或设置附加属性值所需的访问器方法的类型。
The most common scenario for attached properties is to enable child elements to report a property value to their parent element.
附加属性的最常见方案是使子元素能够向其父元素报告属性值。
The following example illustrates the DockPanel.Dock attached property. The DockPanel class defines the accessors for DockPanel.Dock and therefore owns the attached property. The DockPanel class also includes logic that iterates its child elements and specifically checks each element for a set value of DockPanel.Dock. If a value is found, that value is used during layout to position the child elements. Use of the DockPanel.Dock attached property and this positioning capability is in fact the motivating scenario for the DockPanel class.
下面的示例演示了DockPanel.Dock 附加属性。DockPanel 类定义 DockPanel.Dock的访问器,因此拥有附加的属性。 DockPanel 类还包括对子元素进行分验并专门检查每个元素的 DockPanel.Dock的设置值的逻辑。如果找到值,则在布局期间使用该值来定位子元素。使用 DockPanel.Dock 附加属性和此定位功能实际上是 DockPanel类的激励方案。
1 <DockPanel> 2 <Button DockPanel.Dock="Left" Width="100" Height="20">I am on the left</Button> 3 <Button DockPanel.Dock="Right" Width="100" Height="20">I am on the right</Button> 4 </DockPanel>
In WPF, most or all the attached properties are also implemented as dependency properties.
Attached events use a similar ownerType.eventName form of attribute syntax. Just like the non-attached events, the attribute value for an attached event in XAML specifies the name of the handler method that is invoked when the event is handled on the element. Attached event usages in WPF XAML are less common.
附加事件使用属性语法的类似所有者 Type.eventName 形式。与未附加事件一样,XAML 中附加事件的属性值指定在元素上处理事件时调用的处理程序方法的名称。WPF XAML 中附加的事件用法不太常见。
Base types and XAML
基类型和 XAML
Underlying WPF XAML and its XAML namespace is a collection of types that correspond to CLR objects in addition to markup elements for XAML. However, not all classes can be mapped to elements. Abstract classes, such as ButtonBase, and certain non-abstract base classes, are used for inheritance in the CLR objects model. Base classes, including abstract ones, are still important to XAML development because each of the concrete XAML elements inherits members from some base class in its hierarchy. Often these members include properties that can be set as attributes on the element, or events that can be handled. FrameworkElement is the concrete base UI class of WPF at the WPF framework level. When designing UI, you will use various shape, panel, decorator, or control classes, which all derive from FrameworkElement. A related base class, FrameworkContentElement, supports document-oriented elements that work well for a flow layout presentation, using APIs that deliberately mirror the APIs in FrameworkElement. The combination of attributes at the element level and a CLR object model provides you with a set of common properties that are settable on most concrete XAML elements, regardless of the specific XAML element and its underlying type.
基础 WPF XAML 及其 XAML 命名空间是对应于 CLR 对象以及 XAML 标记元素的类型的集合。但是,并非所有类都可以映射到元素。抽象类(如ButtonBase) 和某些非抽象基类用于 CLR 对象模型中的继承。基类(包括抽象类)对于 XAML 开发仍然很重要,因为每个具体的 XAML 元素都继承其层次结构中某个基类的成员。通常,这些成员包括可以设置为元素上的属性的属性,或可处理的事件。框架元素是 WPF 框架级别 WPF 的具体基本 UI 类。设计 UI 时,将使用各种形状、面板、修饰器或控件类,这些类都派生自 FrameworkElement。相关的基类 FrameworkContentElement支持面向文档的元素,这些元素非常适合流布局表示,使用有意镜像框架元素中的 API 的API。元素级别的属性组合和 CLR 对象模型为您提供了一组公共属性,这些属性可在大多数具体的 XAML 元素上设置,而不考虑特定的 XAML 元素及其基础类型。
XAML security
XAML 安全性
XAML is a markup language that directly represents object instantiation and execution. Therefore, elements created in XAML have the same ability to interact with system resources (network access, file system IO, for example) as the equivalent generated code does. XAML loaded in to a fully trusted app has the same access to the system resources as the hosting app does.
XAML 是一种直接表示对象实例化和执行的标记语言。因此,在 XAML 中创建的元素与等效生成的代码具有与系统资源(例如网络访问、文件系统 IO)交互的能力。加载到完全受信任的应用的 XAML 与托管应用具有对系统资源的相同访问权限。
Loading XAML from code
从代码加载 XAML
XAML can be used to define all of the UI, but it is sometimes also appropriate to define just a piece of the UI in XAML. This capability could be used to enable partial customization, local storage of information, using XAML to provide a business object, or a variety of possible scenarios. The key to these scenarios is the XamlReader class and its Load method. The input is a XAML file, and the output is an object that represents all of the run-time tree of objects that was created from that markup. You then can insert the object to be a property of another object that already exists in the app. So long as the property is an appropriate property in the content model that has eventual display capabilities and that will notify the execution engine that new content has been added into the app, you can modify a running app's contents easily by loading in XAML.
XAML 可用于定义所有 UI,但有时也适合在 XAML 中仅定义 UI 的一部分。此功能可用于启用部分自定义、本地信息存储、使用 XAML 提供业务对象或各种可能的方案。这些方案的关键是XamlReader 类及其 Load 方法。输入是 XAML 文件,输出是表示从该标记创建的对象的所有运行时树的对象。然后,可以将该对象插入为应用中已存在的另一个对象的属性。只要该属性是内容模型中具有最终显示功能的相应属性,并且将通知执行引擎新内容已添加到应用中,就可以通过加载 XAML 轻松修改正在运行的应用的内容。