Область видимости имен WPF
Обновлен: Ноябрь 2007
Области видимости имен являются как концепцией, так и программируемыми объектами, которые хранят связи между определенными именами объектов XAML и эквивалентами их экземпляров. Области видимости имен в управляемом коде WPF создаются при загрузке страниц для приложения XAML. Области видимости имен как программируемые объекты определяются интерфейсом INameScope и реализуются также посредством практического класса NameScope.
В этом разделе содержатся следующие подразделы.
- Области видимости имен в загруженных приложениях XAML
- Области видимости имен в стилях и шаблонах
- Области видимости имен и API, связанные с именами
- Связанные разделы
Области видимости имен в загруженных приложениях XAML
Области видимости имен создаются в корневом элементе страницы XAML при обработке страницы. Каждое имя, указанное внутри страницы, добавляется в соответствующую область видимости имен. Элементы, являющиеся общими корневыми элементами (например Page и Window), всегда управляют областью видимости имен. Если такой элемент, как FrameworkElement или FrameworkContentElement, является корневым элементом страницы в разметке, то процессор XAML добавляет корень Page неявно, поэтому Page может предоставить область видимости имен. Область видимости имен создается даже в том случае, если изначально атрибуты Name или x:Name не определены в XAML.
При попытке использования одинакового имени дважды в любой области видимости имен будет вызвано исключение. Для XAML, который имеет фоновый код и является частью скомпилированного приложения, вызывается исключение при создании сгенерированного класса для страницы.
Добавление элементов в деревья проанализированных элементов
Все добавления к дереву элементов после начальной загрузки и обработки должны вызывать соответствующую реализацию RegisterName для класса, определяющего область видимости имен. В противном случае добавленный объект не может быть вызван по имени с помощью таких методов, как FindName. Простое задание свойства Name (или Атрибут x:Name) не зарегистрирует это имя в любой области видимости имен. Добавление именованного элемента в дерево элементов, которое имеет область видимости имен, также не зарегистрирует это имя в области видимости имен. Хотя области видимости имен могут быть вложенными, обычно имена регистрируются в области видимости, которая существует в корневом элементе, таким образом область видимости имен располагается параллельно области видимости, созданной в эквивалентной загруженной странице XAML. Наиболее распространенным сценарием для разработчиков приложений будет использование RegisterName для регистрации имен в области видимости в текущем корне.RegisterName является частью одного важного сценария для поиска раскадровок, которые будут выполняться в качестве анимаций. Дополнительные сведения см. в разделе Общие сведения о Storyboard. При вызове RegisterName в элементе, отличном от корневого элемента в том же логическом дереве, имя по-прежнему будет зарегистрировано в элементе, ближайшем к корню, как если бы RegisterName вызывался в корневом элементе.
Области видимости имен в коде
Для приложений, созданных программно, а не из загруженного XAML, корневой элемент должен реализовать INameScope или быть классом FrameworkElement или производным классом FrameworkContentElement, чтобы поддерживать область видимости имен.
Также для любого элемента, не загруженного и не обработанного процессором XAML, область видимости имен для объекта не создается и не инициализируется по умолчанию. Необходимо явным образом создать новую область видимости имен для любого элемента, для которого требуется затем зарегистрировать имена. Чтобы создать область видимости имен для элемента, вызовите статический метод SetNameScope. Укажите элемент в качестве параметра dependencyObject, и новый конструктор NameScope вызывается в качестве параметра value.
Если объект, предоставленный как dependencyObject для SetNameScope, не является реализацией INameScope, FrameworkElement или FrameworkContentElement, то вызов RegisterName для любых дочерних элементов не будет иметь никакого эффекта. Если при создании новой области видимости имен произойдет сбой, то вызовы RegisterName вызовут исключение.
Пример использования области видимости имен API-интерфейсы в коде см. в разделе Практическое руководство. Определение пространства имен.
Области видимости имен в стилях и шаблонах
Стили и шаблоны в WPF предоставляют возможность повторного использования и применения содержимого простым способом, но стили и шаблоны могут также включать элементы с именами, определенными на уровне шаблона. Затем один и тот же шаблон может использоваться несколько раз на странице. По этой причине стили и шаблоны определяют свои собственные области видимости имен, независимо от содержащей страницы, в которой этот стиль или шаблон применяется.
Рассмотрим следующий пример.
<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>
Здесь один тот же шаблон применяется к двум разным кнопкам. Если шаблоны не имели дискретные области видимости имен, имя TheBorder, используемое в шаблоне, вызовет конфликт имен. Каждый экземпляр шаблона имеет свою собственную область видимости имен, поэтому в данном примере каждая область видимости имен экземпляра шаблона будет содержать ровно одно имя.
Стили также получают собственные области видимости имен, в основном поэтому части областей видимости могут иметь присвоенные индивидуальные имена. Эти имена включают конкретные поведения элемента управления, которые будут целевыми элементами с таким именем, даже если шаблон был переопределен как часть настройки элемента управления.
Из-за независимых областей видимости имен поиск именованных элементов в шаблоне является более затратной задачей, чем поиск нешаблонного элемента на странице. Сначала необходимо определить применяемый шаблон, путем получения значения свойства Template элемента управления, в котором шаблон применяется. Затем вызывается версия шаблона FindName, передающая элемент управления, в котором шаблон применяется в качестве второго параметра.
Если вы являетесь автором элементом управления и создаете соглашение, в котором конкретный именованный элемент в примененном шаблоне является целью для поведения, заданного самим элементом управления, то вы можете использовать метод GetTemplateChild из кода реализации элемента управления. Метод GetTemplateChild является защищенным, поэтому только автор элемента управления имеет доступ к нему.
Если при работе в шаблоне требуется получить область видимости имен, в которой применяется шаблон, получите TemplatedParent, а затем вызовите FindName. В качестве примера работы в шаблоне можно привести ситуацию, когда пишется реализация обработчика событий, в котором событие будет вызвано из элемента в примененном шаблоне.
Области видимости имен и API, связанные с именами
FrameworkElement имеет методы FindName, RegisterName и UnregisterName. Если элемент, вызываемый этими методами, имеет собственную область видимости имен, то методы элемента вызываются в методах области видимости. В противном случае родительский элемент проверяется, чтобы увидеть, что если он имеет собственную область видимости, и этот процесс продолжается рекурсивно до тех пор, пока область видимости имен не будет найдена (из-за того, что поведение процессора XAML, гарантирует наличие области видимости имен в корне). FrameworkContentElement имеет аналогичное поведение, за тем исключением, что нет FrameworkContentElement имеющего собственную область видимости имен. Методы существуют в FrameworkContentElement, так что вызовы могут быть в конечном счете переданы родительскому элементу FrameworkElement.
SetNameScope используется для сопоставления новой области видимости имен с существующим объектом. Можно вызывать SetNameScope несколько раз, чтобы сбросить или очистить область видимости имен, но это не очень распространенный способ использования. Кроме того, GetNameScope обычно не используется из кода.
Реализации области видимости имен
Следующие классы реализуют INameScope непосредственно:
ResourceDictionary не использует области видимости имен; вместо этого он использует ключи, так как это является реализацией хэш-таблицы словаря. Единственная причина, по которой ResourceDictionary реализует INameScope, является то, что он может вызывать исключения в пользовательском коде, которые помогают уточнить различие между верными областями видимости имен и тем, как ResourceDictionary обрабатывает ключи, а также чтобы убедиться, что области видимости в отдельности не применяются к ResourceDictionary при помощи родительских элементов.
FrameworkTemplate и Style реализуют INameScope через явные определения интерфейса. Явные реализации позволяют этим областям видимости имен вести себя условно, когда они доступны через интерфейс INameScope, который определяет, как области видимости имен передаются внутренними процессами WPF. Но явные определения интерфейса не являются частью обычной области API объектов FrameworkTemplate и Style, поскольку редко бывает нужно вызывать методы INameScope непосредственно в FrameworkTemplate и Style.
Следующие классы определяют свои собственные области видимости имен, используя вспомогательный класс System.Windows.NameScope и подключение к его реализации области видимости имен через вложенное свойство NameScope:
См. также
Основные понятия
Пространства имен XAML и сопоставление пространств имен