Поделиться через


Области имен XAML

Область имен XAML сохраняет связи между определенными XAML именами объектов и их эквивалентами экземпляров. Эта концепция аналогична более широкому значению термина namescope в других языках программирования и технологиях.

Как определяются области имен XAML

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

Наиболее типичным применением имени в области имен XAML является прямая ссылка на экземпляр объекта, которая активируется проходом компиляции разметки в качестве действия построения проекта, в сочетании с сгенерированным методом InitializeComponent в шаблонах частичных классов.

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

Дополнительная информация о действиях сборки и XAML.

То, что происходит технически, заключается в том, что сам XAML проходит компилятор разметки одновременно, что XAML и частичный класс, определяющий для кода, компилируются вместе. Каждый элемент объекта с атрибутом Name или x:Name , определенным в разметке, создает внутреннее поле с именем, соответствующим имени XAML. Это поле изначально пусто. Затем класс создает метод InitializeComponent , который вызывается только после загрузки всего XAML. В логике InitializeComponent каждое внутреннее поле затем заполняется возвращаемым значением FindName для эквивалентной строки имени. Вы можете наблюдать эту инфраструктуру самостоятельно, просматривая файлы ".g" (сгенерированные), которые создаются для каждой страницы XAML в подпапке /obj проекта приложения на платформе Windows Runtime после компиляции. Кроме того, поля и метод InitializeComponent отображаются как члены результирующей сборки, если вы выполните отражение или иначе проверите содержание языкового интерфейса.

Замечание

Специально для расширений компонентов Visual C++ (C++/CX) поле резервного копирования для ссылки x:Name не создается для корневого элемента XAML-файла. Если вам нужно ссылаться на корневой объект из кода C++/CX, используйте другие API или обход дерева. Например, можно вызвать FindName для известного дочернего элемента, а затем вызвать Parent.

Создание объектов во время выполнения с помощью XamlReader.Load

XAML также можно использовать в качестве строковых входных данных для метода XamlReader.Load , который действует аналогично начальной операции синтаксического анализа источника XAML. XamlReader.Load создает новое автономное дерево объектов во время выполнения. Затем отключенное дерево может быть присоединено к некоторой точке в дереве основного объекта. Необходимо явно подключить созданное дерево объектов, добавив его в коллекцию свойств содержимого, например "Дочерние", или задав другое свойство, которое принимает значение объекта (например, загрузка нового объекта ImageBrush для значения свойства Fill ).

Последствия использования XamlReader.Load для области имен XAML

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

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

При вызове FindName для получения именованного объекта в корневой области имен XAML, метод не найдет объекты из дискретной области имен XAML, созданной XamlReader.Load. И наоборот, если вызвать FindName из объекта, полученного вне дискретных областей имен XAML, метод не найдет именованные объекты в корневых областях имен XAML.

Эта дискретная проблема с областью имен XAML влияет только на поиск объектов по имени в области имен XAML при использовании вызова FindName .

Чтобы получить ссылки на объекты, определенные в другой области имен XAML, можно использовать несколько методов:

  • Обходите все дерево дискретными шагами с помощью свойств родителя и/или коллекций, которые известны как существующие в структуре вашего дерева объектов (например, коллекция, возвращаемая Panel.Children).
  • Если вы вызываете из отдельной области имен XAML и хотите получить корневую область имен XAML, всегда легко получить ссылку на главное окно, которое в настоящее время отображается. Вы можете получить визуальный корень (корневой элемент XAML, также известный как источник содержимого) из текущего окна приложения в одной строке кода с вызовом Window.Current.Content. Затем вы можете привести к FrameworkElement и вызвать FindName из этой области.
  • Если вы вызываете из корневой области имен XAML и хотите получить объект, находящийся в дискретной области имен XAML, лучше всего сразу предусмотреть в коде и сохранить ссылку на объект, возвращенный с помощью XamlReader.Load, и затем добавьте его в основное дерево объектов. Теперь этот объект является допустимым объектом для вызова FindName в дискретной области имен XAML. Этот объект можно сохранить в виде глобальной переменной или передать его с помощью параметров метода.
  • Вы можете избежать проблем с именами и областью имен XAML, проверив визуальное дерево. API VisualTreeHelper позволяет просматривать визуальное дерево с точки зрения родительских объектов и дочерних коллекций, основанных исключительно на позиции и индексе.

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

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

<Page
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"  >
  <Page.Resources>
    <ControlTemplate x:Key="MyTemplate">
      ....
      <TextBlock x:Name="MyTextBlock" />
    </ControlTemplate>
  </Page.Resources>
  <StackPanel>
    <SomeControl Template="{StaticResource MyTemplate}" />
    <SomeControl Template="{StaticResource MyTemplate}" />
  </StackPanel>
</Page>

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

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