Расширения разметки и XAML WPFMarkup Extensions and WPF XAML

В этом разделе рассматриваются концепции расширений разметки для XAML, включая их синтаксические правила, назначение и формирующую их объектную модель классов.This topic introduces the concept of markup extensions for XAML, including their syntax rules, purpose, and the class object model that underlies them. Расширения разметки — это общая функция языка XAML и реализация служб XAML платформы .NET.Markup extensions are a general feature of the XAML language and of the .NET implementation of XAML services. В этом разделе рассматриваются расширения разметки для использования в XAML WPF.This topic specifically details markup extensions for use in WPF XAML.

Обработчики XAML и расширения разметкиXAML Processors and Markup Extensions

В целом средство синтаксического анализа XAML может интерпретировать значение атрибута как строковый литерал, который можно преобразовать в примитив, или преобразовать его в объект каким-либо способом.Generally speaking, a XAML parser can either interpret an attribute value as a literal string that can be converted to a primitive, or convert it to an object by some means. Один из таких способов заключается в обращении к преобразователю типов. Это описывается в разделе Преобразователи типов и XAML.One such means is by referencing a type converter; this is documented in the topic TypeConverters and XAML. Однако существуют сценарии, где требуется другое поведение.However, there are scenarios where different behavior is required. Например, обработчику XAML можно указать, что значение атрибута не должно порождать новый объект в графе объектов.For example, a XAML processor can be instructed that a value of an attribute should not result in a new object in the object graph. Вместо этого атрибут должен обеспечить граф объектов, который ссылается на уже созданный объект в другой части графа или на статический объект.Instead, the attribute should result in an object graph that makes a reference to an already constructed object in another part of the graph, or a static object. В другом сценарии обработчик XAML может получить указание использовать синтаксис, предоставляющий конструктору объекта аргументы, отличные от аргументов по умолчанию.Another scenario is that a XAML processor can be instructed to use a syntax that provides non-default arguments to the constructor of an object. Это типы сценариев, где расширение разметки может предоставить решение.These are the types of scenarios where a markup extension can provide the solution.

Базовый синтаксис расширения разметкиBasic Markup Extension Syntax

Расширение разметки можно реализовать для предоставления значений атрибутов при использовании атрибутов, свойств при использовании элементов свойств или и того и другого.A markup extension can be implemented to provide values for properties in an attribute usage, properties in a property element usage, or both.

При использовании расширения разметки для предоставления значения атрибута синтаксис, который позволяет обработчику XAML различать последовательность расширения разметки, подразумевает наличие открывающей и закрывающей фигурных скобок ({ и }).When used to provide an attribute value, the syntax that distinguishes a markup extension sequence to a XAML processor is the presence of the opening and closing curly braces ({ and }). Затем тип расширения разметки определяется по токену строки, следующему сразу после открывающей фигурной скобки.The type of markup extension is then identified by the string token immediately following the opening curly brace.

При использовании в синтаксисе элемента свойства расширение разметки визуально не отличается от любого другого элемента, используемого для предоставления значения элемента свойства: объявление элемента XAML, которое ссылается на класс расширения разметки как на элемент, заключается в угловые скобки (<>).When used in property element syntax, a markup extension is visually the same as any other element used to provide a property element value: a XAML element declaration that references the markup extension class as an element, enclosed within angle brackets (<>).

Расширения разметки, определенные в XAMLXAML-Defined Markup Extensions

Существует несколько расширений разметки, которые не относятся к реализации WPF XAML, но являются реализациями внутренних параметров или функций XAML как языка.Several markup extensions exist that are not specific to the WPF implementation of XAML, but are instead implementations of intrinsics or features of XAML as a language. Эти расширения разметки реализуются в сборке System.Xaml как часть общих служб .NET Framework XAML и находятся в пространстве имен XAML языка XAML.These markup extensions are implemented in the System.Xaml assembly as part of the general .NET Framework XAML services, and are within the XAML language XAML namespace. В обычном синтаксисе разметки эти расширения разметки обычно распознаются по префиксу x:.In terms of common markup usage, these markup extensions are typically identifiable by the x: prefix in the usage. Базовый класс MarkupExtension (также определенный в System. XAML) предоставляет шаблон, который все расширения разметки должны использовать для поддержки в средствах чтения и записи XAML, включая в WPF XAML.The MarkupExtension base class (also defined in System.Xaml) provides the pattern that all markup extensions should use in order to be supported in XAML readers and XAML writers, including in WPF XAML.

  • x:Type предоставляет объект Type для именованного типа.x:Type supplies the Type object for the named type. Это средство наиболее часто используется в стилях и шаблонах.This facility is used most frequently in styles and templates. Дополнительные сведения см. в разделе Расширение разметки x:Type.For details, see x:Type Markup Extension.

  • x:Static создает статические значения.x:Static produces static values. Эти значения поступают из сущностей кода типа значения, которые непосредственно не принадлежат к типу значения целевого свойства, но могут быть приведены к нему.The values come from value-type code entities that are not directly the type of a target property's value, but can be evaluated to that type. Дополнительные сведения см. в разделе Расширение разметки x:Static.For details, see x:Static Markup Extension.

  • x:Null задает null как значение для свойства и может использоваться для атрибутов или значений элементов свойств.x:Null specifies null as a value for a property and can be used either for attributes or property element values. Дополнительные сведения см. в разделе Расширение разметки x:NULL.For details, see x:Null Markup Extension.

  • x:Array обеспечивает поддержку создания общих массивов в синтаксисе XAML для случаев, когда поддержка коллекций, предоставляемая базовыми элементами и моделями элементов управления WPF, намеренно не используется.x:Array provides support for creation of general arrays in XAML syntax, for cases where the collection support provided by WPF base elements and control models is deliberately not used. Дополнительные сведения см. в разделе Расширение разметки x:Array.For details, see x:Array Markup Extension.

Примечание

Префикс x: используется для обычного сопоставления пространства имен XAML внутренних параметров языка XAML в корневом элементе файла или рабочей среды XAML.The x: prefix is used for the typical XAML namespace mapping of the XAML language intrinsics, in the root element of a XAML file or production. Например, шаблоны Visual Studio для приложений WPF инициируют XAML-файл с помощью этого x: сопоставления.For example, the Visual Studio templates for WPF applications initiate a XAML file using this x: mapping. Можно выбрать другой маркер префикса в собственном сопоставлении пространства имен XAML, но в этой документации предполагается использование сопоставления по умолчанию x: как средства идентификации этих сущностей, которые являются определенной частью пространства имен XAML для языка XAML, в отличие от пространства имен WPF по умолчанию или других пространств имен XAML, не связанных с конкретной платформой.You could choose a different prefix token in your own XAML namespace mapping, but this documentation will assume the default x: mapping as a means of identifying those entities that are a defined part of the XAML namespace for the XAML language, as opposed to the WPF default namespace or other XAML namespaces not related to a specific framework.

Расширения разметки для WPFWPF-Specific Markup Extensions

Наиболее распространенными расширениями разметки, используемыми в программировании WPF, являются те, которые поддерживают ссылки на ресурсы (StaticResource и DynamicResource) и те, которые поддерживают привязку данных (Binding).The most common markup extensions used in WPF programming are those that support resource references (StaticResource and DynamicResource), and those that support data binding (Binding).

  • StaticResource обеспечивает значение для свойства, заменяя значение уже заданного ресурса.StaticResource provides a value for a property by substituting the value of an already defined resource. Оценка StaticResource в конечном счете выполняется во время загрузки XAML и не имеет доступа к графу объектов во время выполнения.A StaticResource evaluation is ultimately made at XAML load time and does not have access to the object graph at run time. Дополнительные сведения см. в разделе Расширение разметки StaticResource.For details, see StaticResource Markup Extension.

  • DynamicResource обеспечивает значение для свойства в виде ссылки на ресурс, отложенной до времени выполнения.DynamicResource provides a value for a property by deferring that value to be a run-time reference to a resource. Ссылка на динамический ресурс вызывает новый поиск каждый раз, когда осуществляется доступ к такому ресурсу, и имеет доступ к графу объектов во время выполнения.A dynamic resource reference forces a new lookup each time that such a resource is accessed and has access to the object graph at run time. Для получения такого доступа концепция DynamicResource поддерживается свойствами зависимостей в системе свойств WPF и вычисляемыми выражениями.In order to get this access, DynamicResource concept is supported by dependency properties in the WPF property system, and evaluated expressions. Таким образом, вы можете использовать DynamicResource только для целевого свойства зависимостей.Therefore you can only use DynamicResource for a dependency property target. Дополнительные сведения см. в разделе Расширение разметки DynamicResource.For details, see DynamicResource Markup Extension.

  • Binding предоставляет для свойства привязанное к данным значение, используя контекст данных, который применяется к родительскому объекту во время выполнения.Binding provides a data bound value for a property, using the data context that applies to the parent object at run time. Это расширение разметки довольно сложное, поскольку разрешает использовать важный встроенный синтаксис для указания привязки данных.This markup extension is relatively complex, because it enables a substantial inline syntax for specifying a data binding. Дополнительные сведения см. в разделе Привязка расширения разметки.For details, see Binding Markup Extension.

  • RelativeSource предоставляет сведения об источнике для Binding, который может перемещаться по нескольким возможным связям в дереве объектов времени выполнения.RelativeSource provides source information for a Binding that can navigate several possible relationships in the run-time object tree. Это обеспечивает специализированные источники для привязок, которые создаются в шаблонах для многократного использования или в коде без полных сведений об окружающем дереве объектов.This provides specialized sourcing for bindings that are created in multi-use templates or created in code without full knowledge of the surrounding object tree. Дополнительные сведения см. в разделе Расширение разметки RelativeSource.For details, see RelativeSource MarkupExtension.

  • TemplateBinding позволяет шаблону элемента управления использовать значения для шаблонных свойств, получаемых из определенных объектной моделью свойств класса, который будет использовать этот шаблон.TemplateBinding enables a control template to use values for templated properties that come from object-model-defined properties of the class that will use the template. Другими словами, свойство в определении шаблона может получить доступ к контексту, который существует только после применения шаблона.In other words, the property within the template definition can access a context that only exists once the template is applied. Дополнительные сведения см. в разделе Расширение разметки TemplateBinding.For details, see TemplateBinding Markup Extension. Дополнительные сведения о практическом применении TemplateBinding см. в разделе Пример задания стиля с помощью ControlTemplates.For more information on the practical use of TemplateBinding, see Styling with ControlTemplates Sample.

  • ColorConvertedBitmap поддерживает сравнительно сложный сценарий создания образов.ColorConvertedBitmap supports a relatively advanced imaging scenario. Дополнительные сведения см. в разделе Расширение разметки ColorConvertedBitmap.For details, see ColorConvertedBitmap Markup Extension.

  • ComponentResourceKey и ThemeDictionary поддерживают аспекты поиска ресурсов, в честности ресурсов и тем, упакованных в пользовательские элементы управления.ComponentResourceKey and ThemeDictionary support aspects of resource lookup, particularly for resources and themes that are packaged with custom controls. Дополнительные сведения см. в разделе Расширение разметки ComponentResourceKey, Расширение разметки ThemeDictionary или Общие сведения о разработке элементов управления.For more information, see ComponentResourceKey Markup Extension, ThemeDictionary Markup Extension, or Control Authoring Overview.

Классы расширений **Extension Classes

Как для общего языка XAML, так и для расширений разметки WPF поведение каждого расширения разметки определяется обработчиком XAML через класс *Extension, производный от MarkupExtension, и предоставляет реализацию метода ProvideValue.For both the general XAML language and WPF-specific markup extensions, the behavior of each markup extension is identified to a XAML processor through a *Extension class that derives from MarkupExtension, and provides an implementation of the ProvideValue method. Этот метод в каждом расширении предоставляет объект, который возвращается при вычислении расширения разметки.This method on each extension provides the object that is returned when the markup extension is evaluated. Возвращаемый объект обычно вычисляется, исходя из различных токенов строк, передаваемых в расширение разметки.The returned object is typically evaluated based on the various string tokens that are passed to the markup extension.

Например, класс StaticResourceExtension предоставляет реализацию фактического уточняющего запроса ресурса, чтобы его ProvideValue реализация возвращала запрошенный объект, а вход этой конкретной реализации — строка, которая используется для поиска ресурс по его x:Keyу.For example, the StaticResourceExtension class provides the surface implementation of actual resource lookup so that its ProvideValue implementation returns the object that is requested, with the input of that particular implementation being a string that is used to look up the resource by its x:Key. Большая часть подробностей этой реализации не важна при использовании существующего расширения разметки.Much of this implementation detail is unimportant if you are using an existing markup extension.

Некоторые расширения разметки не используют аргументы токенов строк.Some markup extensions do not use string token arguments. Это происходит либо потому, что они возвращают статическое или согласованное значение, либо потому, что контекст для значения, которое должно быть возвращено, доступен посредством одной из служб, передаваемых через параметр serviceProvider.This is either because they return a static or consistent value, or because context for what value should be returned is available through one of the services passed through the serviceProvider parameter.

Шаблон именования *Extension принят для удобства и согласованности.The *Extension naming pattern is for convenience and consistency. Он не требуется, чтобы обработчик XAML определил этот класс как поддерживающий расширение разметки.It is not necessary in order for a XAML processor to identify that class as support for a markup extension. До тех пор, пока база кода включает System. XAML и использует .NET Framework реализации служб XAML, все, что необходимо распознать как расширение разметки XAML, должно быть производным от MarkupExtension и поддерживать синтаксис конструкции.So long as your codebase includes System.Xaml and uses .NET Framework XAML Services implementations, all that is necessary to be recognized as a XAML markup extension is to derive from MarkupExtension and to support a construction syntax. WPF определяет классы, разрешающие расширения разметки, которые не соответствуют шаблону именования *Extension, например Binding.WPF defines markup extension-enabling classes that do not follow the *Extension naming pattern, for example Binding. Обычно причина заключается в том, что класс поддерживает не только расширение разметки, но и сценарии.Typically the reason for this is that the class supports scenarios beyond pure markup extension support. В случае Bindingэтот класс поддерживает доступ во время выполнения к методам и свойствам объекта для сценариев, которые ничего не делают с XAML.In the case of Binding, that class supports run-time access to methods and properties of the object for scenarios that have nothing to do with XAML.

Интерпретация текста инициализации класса ExtensionExtension Class Interpretation of Initialization Text

Токены строки, следующие именем расширения разметки и по-прежнему заключенные в фигурные скобки, интерпретируются обработчиком XAML одним из следующих способов.The string tokens following the markup extension name and still within the braces are interpreted by a XAML processor in one of the following ways:

  • Запятая всегда представляет разделитель отдельных токенов.A comma always represents the separator or delimiter of individual tokens.

  • Если отдельные разделенные токены не содержат знаки равенства, каждый токен считается аргументом конструктора.If the individual separated tokens do not contain any equals signs, each token is treated as a constructor argument. Каждый параметр конструктора должен передаваться в качестве типа, ожидаемого сигнатурой, и в соответствующем порядке, ожидаемом сигнатурой.Each constructor parameter must be given as the type expected by that signature, and in the proper order expected by that signature.

    Примечание

    Обработчик XAML должен вызвать конструктор, который соответствует количеству аргументов числа пар.A XAML processor must call the constructor that matches the argument count of the number of pairs. По этой причине при реализации пользовательского расширения разметки не следует предоставлять несколько конструкторов с одинаковым числом аргументов.For this reason, if you are implementing a custom markup extension, do not provide multiple constructors with the same argument count. Поведение для обработчика XAML при наличии нескольких путей конструктора расширения разметки с одинаковым количеством параметров не определено, но следует помнить, что обработчику XAML разрешено создавать исключение для использования при возникновении такой ситуации в определениях типов расширения разметки.The behavior for how a XAML processor behaves if more than one markup extension constructor path with the same parameter count exists is not defined, but you should anticipate that a XAML processor is permitted to throw an exception on usage if this situation exists in the markup extension type definitions.

  • Если отдельные разделенные маркеры содержат знаки равенства, то обработчик XAML сначала вызывает конструктор без параметров для расширения разметки.If the individual separated tokens contain equals signs, then a XAML processor first calls the parameterless constructor for the markup extension. Затем каждая пара «имя = значение» интерпретируется как имя свойства, которое существует в расширении разметки, и значение для присвоения этому свойству.Then, each name=value pair is interpreted as a property name that exists on the markup extension, and a value to assign to that property.

  • Если имеется параллельный результат между поведением конструктора и поведением установки свойства в расширении разметки, не имеет значения, какое поведение использовать.If there is a parallel result between the constructor behavior and the property setting behavior in a markup extension, it does not matter which behavior you use. Чаще всего пары свойство=значение используются для расширений разметки, которые имеют несколько устанавливаемых свойств, поскольку это делает разметку более продуманной и уменьшает вероятность случайно перепутать параметры конструктора.It is more common usage to use the property=value pairs for markup extensions that have more than one settable property, if only because it makes your markup more intentional and you are less likely to accidentally transpose constructor parameters. (При указании пар свойство = значение эти свойства могут быть в любом порядке.) Кроме того, нет никакой гарантии, что расширение разметки предоставляет параметр конструктора, который задает каждое из его устанавливаемых свойств.(When you specify property=value pairs, those properties may be in any order.) Also, there is no guarantee that a markup extension supplies a constructor parameter that sets every one of its settable properties. Например, Binding является расширением разметки, со множеством свойств, устанавливаемых с помощью расширения в форме свойства=значение , но Binding поддерживает только два конструктора: конструктор без параметров и один, который задает Начальный путь.For example, Binding is a markup extension, with many properties that are settable through the extension in property=value form, but Binding only supports two constructors: a parameterless constructor, and one that sets an initial path.

  • Литерал запятой нельзя передать в расширение разметки без escape-последовательности.A literal comma cannot be passed to a markup extension without escapement.

Escape-последовательности и расширения разметкиEscape Sequences and Markup Extensions

При обработке атрибутов в обработчик XAML фигурные скобки расцениваются как указание на последовательность расширения разметки.Attribute handling in a XAML processor uses the curly braces as indicators of a markup extension sequence. При необходимости можно также получить литеральный символ фигурной скобки, введя escape-последовательность с помощью пары пустых фигурных скобок, за которыми следует литерал фигурной скобки.It is also possible to produce a literal curly brace character attribute value if necessary, by entering an escape sequence using an empty curly brace pair followed by the literal curly brace. См. раздел {} escape-последовательности — расширение разметки.See {} Escape Sequence - Markup Extension.

Вложенные расширения разметки при использовании XAMLNesting Markup Extensions in XAML Usage

Поддерживается вложение нескольких расширений разметки, и каждое расширение разметки будет вычисляться последовательно, начиная с самого глубокого.Nesting of multiple markup extensions is supported, and each markup extension will be evaluated deepest first. Рассмотрим следующий пример.For example, consider the following usage:

<Setter Property="Background"  
  Value="{DynamicResource {x:Static SystemColors.ControlBrushKey}}" />  

При таком использовании инструкция x:Static оценивается первой и возвращает строку.In this usage, the x:Static statement is evaluated first and returns a string. Затем эта строка используется в качестве аргумента для DynamicResource.That string is then used as the argument for DynamicResource.

Расширения разметки и синтаксис элементов свойствMarkup Extensions and Property Element Syntax

При использовании в качестве объектного элемента, заполняющего значение элемента свойства, класс расширения разметки визуально неотличим от обычного объектного элемента с поддержкой типа, который может использоваться в XAML.When used as an object element that fills a property element value, a markup extension class is visually indistinguishable from a typical type-backed object element that can be used in XAML. Практическое различие между обычным объектным элементом и расширением разметки заключается в том, что расширение разметки либо вычисляется в типизированное значение, либо откладывается как выражение.The practical difference between a typical object element and a markup extension is that the markup extension is either evaluated to a typed value or deferred as an expression. Поэтому механизмы для каких-либо возможных ошибок типов значений свойств для расширения разметки будут отличаться, аналогично тому, как свойство с поздним связыванием обрабатывается в других моделях программирования.Therefore the mechanisms for any possible type errors of property values for the markup extension will be different, similar to how a late-bound property is treated in other programming models. Обычный объектный элемент будет вычисляться на соответствие типа целевому свойству, устанавливаемому при анализе XAML.An ordinary object element will be evaluated for type match against the target property it is setting when the XAML is parsed.

Большинство расширений разметки, если они используются в синтаксисе объектных элементов для заполнения элемента свойства, не имеют содержимого или какого-либо другого синтаксиса элементов свойств внутри.Most markup extensions, when used in object element syntax to fill a property element, would not have content or any further property element syntax within. Таким образом, будет закрыт тег объектного элемента и не будут предоставлены дочерние элементы.Thus you would close the object element tag, and provide no child elements. Всякий раз, когда обработчик XAML обнаруживает объектный элемент, вызывается конструктор для этого класса, который создает экземпляр объекта, созданного из проанализированного элемента.Whenever any object element is encountered by a XAML processor, the constructor for that class is called, which instantiates the object created from the parsed element. Класс расширения разметки не отличается: Если вы хотите, чтобы расширение разметки можно было использовать в синтаксисе объектного элемента, необходимо предоставить конструктор без параметров.A markup extension class is no different: if you want your markup extension to be usable in object element syntax, you must provide a parameterless constructor. Некоторые существующие расширения разметки имеют по крайней мере одно обязательное значение свойства, которое должно быть указано для эффективной инициализации.Some existing markup extensions have at least one required property value that must be specified for effective initialization. В таком случае это значение свойства обычно передается в объектный элемент объекта качестве атрибута свойства.If so, that property value is typically given as a property attribute on the object element. В справочных страницах Возможности пространства имен языка XAML (x:) и Расширения XAML WPF будут отмечены расширения разметки, которые имеют обязательные свойства (и имена обязательных свойств).In the XAML Namespace (x:) Language Features and WPF XAML Extensions reference pages, markup extensions that have required properties (and the names of required properties) will be noted. В справочных страницах также будут отмечено, если для определенных расширений разметки запрещен синтаксис атрибутов или синтаксис объектных элементов.Reference pages will also note if either object element syntax or attribute syntax is disallowed for particular markup extensions. Важным случаем является расширение разметки x:Array, которое не поддерживает синтаксис атрибутов, так как содержимое этого массива должно быть указано в тегах как содержимое.A notable case is x:Array Markup Extension, which cannot support attribute syntax because the contents of that array must be specified within the tagging as content. Содержимое массива обрабатывается как общие объекты, поэтому нецелесообразно применение для атрибута преобразователей типа по умолчанию.The array contents are handled as general objects, therefore no default type converter for the attribute is feasible. Кроме того, расширение разметки x:Array требует параметр type.Also, x:Array Markup Extension requires a type parameter.

См. такжеSee also