Области видимости имен XAML в WPF

Области видимости имен XAML — это понятие, которое идентифицирует объекты, определенные в XAML. Имена из области видимости имен XAML можно использовать для установления связей между именами объектов, определенными в XAML, и эквивалентными им экземплярами из дерева объектов. Области видимости имен XAML в управляемом коде WPF, как правило, создаются при загрузке отдельных корневых страниц XAML для приложения XAML. Области видимости имен XAML как программируемые объекты определяются интерфейсом INameScope и реализуются также посредством практического класса NameScope.

В этом разделе содержатся следующие подразделы.

  • Области видимости имен в загруженных приложениях XAML
  • Области видимости имен XAML в стилях и шаблонах
  • Области видимости имен XAML и интерфейсы API, связанные с именами
  • Связанные разделы

Области видимости имен в загруженных приложениях XAML

В более широком контексте программирования или вычислительной техники в концепции программирования включается принцип уникального идентификатора или имени, которое можно использовать для доступа к объекту. В системах, где используются идентификаторы или имена, область видимости имен определяет границы, в пределах которых процесс или технология ищет объект с запрошенным именем, или границы, в пределах которых применяются уникальные имена. Эти общие принципы действительны и для областей видимости имен XAML. В WPF области видимости имен XAML создаются в корневом элементе страницы XAML при загрузке страницы. Каждое имя, указанное внутри XAML-страницы, начиная с корневой страницы, добавляется в соответствующую область видимости имен XAML.

В языке XAML системы WPF элементы, являющиеся общими корневыми элементами (например, Page и Window), всегда управляют областью видимости имен XAML. Если такой элемент, как FrameworkElement или FrameworkContentElement, является корневым элементом страницы в разметке, то обработчик XAML неявно добавляет корень Page, чтобы элемент управления Page мог предоставить рабочую область видимости имен XAML.

ПримечаниеПримечание

Область видимости имен XAML создается для производственного приложения XAML при выполнении действий построения WPF, даже если атрибуты Name и x:Name не определены в элементах разметки XAML.

При попытке использования одинакового имени дважды в любой области видимости имен XAML будет вызвано исключение. Для кода XAML системы WPF, которые содержит код программной части и является компонентом скомпилированного приложения, во время первоначальной компиляции разметки при создании сформированного класса для страницы вызывается исключение при выполнении действий построения WPF. Для кода XAML, разметка которого не скомпилирована действием построения, исключения, связанные с проблемами области видимости имен XAML, могут вызываться при загрузке кода XAML. Разработчики XAML должны также учитывать возможность возникновения проблем области видимости имен XAML во время разработки.

Добавление в дерево объектов среды выполнения

Область видимости имен XAML системы WPF создается и определяется в момент синтаксического анализа кода XAML. Если объект добавляется в дерево объектов уже после того, как выполнен синтаксический анализ кода XAML, сформировавшего это дерево, значение Name или x:Name нового объекта не приводит к автоматическому обновлению сведений из области видимости имен XAML. Чтобы добавить имя объекта в область видимости имен XAML системы WPF после загрузки кода XAML, необходимо вызвать соответствующую реализацию метода RegisterName для объекта, который определяет область видимости имен XAML (как правило, для корневой страницы XAML). Если имя не зарегистрировано, на добавленный объект нельзя ссылаться по имени с помощью таких методов, как FindName. Кроме того, такое имя нельзя использовать при подготовке для анимации.

Наиболее распространенным сценарием для разработчиков приложений является использование метода RegisterName для регистрации имен в области видимости XAML в текущем корне страницы. Метод RegisterName является частью важного сценария для раскадровок, которые подготавливают объекты для анимаций. Дополнительные сведения см. в разделе Общие сведения о Storyboard.

При вызове метода RegisterName для объекта, отличного от объекта, который определяет область видимости имен XAML, имя по-прежнему будет зарегистрировано в области видимости имен XAML, содержащей вызывающий объект, как если бы метод RegisterName вызывался для объекта, определяющего эту область видимости имен XAML.

Области видимости имен XAML в коде

Можно создавать и использовать области видимости имен XAML в коде. Интерфейсы API и понятия, участвующие в создании областей видимости XAML, совпадают с применяемыми в чистом коде, поскольку обработчик XAML для WPF использует эти API и понятия при обработке самого кода XAML. Они существуют в основном для поиска объектов по имени в дереве объектов, которое, как правило, частично или полностью задано в XAML.

Для приложений, создаваемых программным путем, а не из загруженного кода XAML, объект, определяющий область видимости имен XAML, должен реализовывать интерфейс INameScope или быть классом, производным от класса FrameworkElement или FrameworkContentElement, чтобы поддерживать создание области видимости имен XAML в своих экземплярах.

Также для любого элемента, не загруженного и не обработанного обработчиком XAML, область видимости имен XAML для объекта не создается и не инициализируется по умолчанию. Необходимо явным образом создать новую область видимости имен XAML для любого объекта, в котором впоследствии требуется зарегистрировать имена. Чтобы создать область видимости имен XAML для элемента, вызовите статический метод SetNameScope. Укажите объект, являющийся его владельцем, в качестве параметра dependencyObject и новый конструктор NameScope в качестве параметра value.

Если объект, предоставленный как dependencyObject для метода SetNameScope, не является реализацией INameScope либо классом FrameworkElement или FrameworkContentElement, то вызов метода RegisterName для любых дочерних элементов не приведет ни к какому результату. Если при создании новой области видимости имен XAML произойдет сбой, то вызовы метода RegisterName вызовут исключение.

Пример использования интерфейсов API для области видимости имен XAML в коде см. в разделе Практическое руководство. Определение пространства имен.

Области видимости имен XAML в стилях и шаблонах

Стили и шаблоны WPF позволяют повторно использовать и применять содержимое простым и понятным способом. Однако стили и шаблоны могут также включать элементы с именами XAML, определенными на уровне шаблона. Затем один и тот же шаблон может использоваться несколько раз на странице. По этой причине стили и шаблоны определяют свои собственные области видимости имен XAML, независимо от расположения в дереве объектов, где применяется стиль или шаблон.

Рассмотрим следующий пример.

<Page
  xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"
  >
  <Page.Resources>
    <ControlTemplate x:Key="MyButtonTemplate" TargetType="{x:Type Button}">
      <Border BorderBrush="Red" Name="TheBorder" BorderThickness="2">
        <ContentPresenter/>
      </Border>      
    </ControlTemplate>
  </Page.Resources>
  <StackPanel>
    <Button Template="{StaticResource MyButtonTemplate}">My first button</Button>
    <Button Template="{StaticResource MyButtonTemplate}">My second button</Button>
  </StackPanel>
</Page>

Здесь один тот же шаблон применяется к двум разным кнопкам. Если у шаблонов не было дискретных областей видимости имен XAML, имя TheBorder, используемое в шаблоне, вызовет конфликт имен в области видимости имен XAML. Каждый экземпляр шаблона имеет свою собственную область видимости имен XAML, поэтому в данном примере каждая область видимости имен экземпляра шаблона будет содержать ровно одно имя.

Стили также определяют собственные области видимости имен XAML, в основном поэтому части раскадровок могут иметь присвоенные индивидуальные имена. Эти имена включают конкретные поведения элемента управления, которые будут целевыми элементами с таким именем, даже если шаблон был переопределен как часть настройки элемента управления.

Из-за независимых областей видимости имен XAML поиск именованных элементов в шаблоне является более затратной задачей, чем поиск нешаблонного именованного элемента на странице. Сначала необходимо определить применяемый шаблон, путем получения значения свойства Template элемента управления, в котором шаблон применяется. Затем вызывается версия шаблона FindName, передающая элемент управления, в котором шаблон применяется в качестве второго параметра.

Если вы являетесь автором элементом управления и создаете соглашение, в котором конкретный именованный элемент в примененном шаблоне является целью для поведения, заданного самим элементом управления, то вы можете использовать метод GetTemplateChild из кода реализации элемента управления. Метод GetTemplateChild является защищенным, поэтому только автор элемента управления имеет доступ к нему.

Если при работе в шаблоне требуется получить область видимости имен XAML, в которой применяется шаблон, получите значение свойства TemplatedParent, а затем вызовите метод FindName. В качестве примера работы в шаблоне можно привести ситуацию, когда пишется реализация обработчика событий, в котором событие будет вызвано из элемента в примененном шаблоне.

Области видимости имен XAML и интерфейсы API, связанные с именами

FrameworkElement имеет методы FindName, RegisterName и UnregisterName. Если объект, вызываемый этими методами, имеет собственную область видимости имен XAML, то методы элемента вызываются в методах соответствующей области видимости XAML. В противном случае проверяется, владеет ли родительский элемент собственной областью видимости имен XAML, и этот процесс продолжается рекурсивно до тех пор, пока область видимости имен не будет найдена (из-за того, что поведение обработчика XAML гарантирует наличие области видимости имен XAML в корне). У FrameworkContentElement аналогичное поведение, за тем исключением, что у FrameworkContentElement никогда не будет собственной области видимости имен XAML. Методы существуют в FrameworkContentElement, так что вызовы могут быть в конечном счете переданы родительскому элементу FrameworkElement.

SetNameScope используется для сопоставления новой области видимости имен XAML с существующим объектом. Можно вызывать метод SetNameScope несколько раз, чтобы сбросить или очистить область видимости имен XAML, но он предназначен не для этого. Кроме того, GetNameScope обычно не используется из кода.

Реализации области видимости имен XAML

Следующие классы реализуют INameScope непосредственно:

ResourceDictionary не использует области видимости имен XAML. Вместо этого он использует ключи, так как это является реализацией словаря. Единственная причина, по которой ResourceDictionary реализует INameScope, является то, что он может вызывать исключения в пользовательском коде, которые помогают уточнить различие между верными областями видимости имен XAML и тем, как ResourceDictionary обрабатывает ключи, а также чтобы убедиться, что области видимости в отдельности не применяются к ResourceDictionary при помощи родительских элементов.

FrameworkTemplate и Style реализуют INameScope через явные определения интерфейса. Явные реализации позволяют этим областям видимости имен XAML вести себя условно, когда они доступны через интерфейс INameScope, который определяет, как области видимости имен XAML передаются внутренними процессами WPF. Но явные определения интерфейса не являются частью обычной области API объектов FrameworkTemplate и Style, поскольку редко бывает нужно вызывать методы INameScope непосредственно в FrameworkTemplate и Style, а вместо этого используется другой интерфейс API, такой как GetTemplateChild.

Следующие классы определяют свои собственные области видимости имен XAML, используя вспомогательный класс System.Windows.NameScope и подключая к его реализации области видимости имен через вложенное свойство NameScope.NameScope:

См. также

Ссылки

Директива x:Name

Основные понятия

Пространства имен XAML и сопоставление пространств имен для WPF XAML