WPF XAML Namescopes
XAML namescopes are a concept, and are represented by objects that store relationships between the XAML defined names of objects and their instance equivalents. XAML namescopes in the WPF managed code are created while loading the pages for a XAML application. XAML namescopes as the programming object are defined by the INameScope interface and are also implemented by the practical class NameScope.
This topic contains the following sections.
- Namescopes in Loaded XAML Applications
- XAML Namescopes in Styles and Templates
- XAML Namescopes and Name-related APIs
- Related Topics
Namescopes in Loaded XAML Applications
In a broader programming or computer science context, programming concepts often include the principle of a unique identifier or name that can be used to access an object. For systems that use identifiers or names like this, the namescope defines the boundaries of where a program or technique will look if an object of that name is requested, or the boundaries wherein uniqueness of names is enforced. XAML namescopes are created on the root element for a XAML page when the page is processed. Each name specified within the XAML page is added to a pertinent XAML namescope. Elements that are common root elements (such as Page, and Window) always control a XAML namescope. If an element such as FrameworkElement or FrameworkContentElement is the root element of the page in markup, a XAML processor adds a Page root implicitly so that the Page can provide a XAML namescope. A XAML namescope is created even if no Name or x:Name attributes are defined on any elements in the XAML initially.
If you try to use the same name twice in any XAML namescope, an exception is raised. For XAML that has code-behind and is part of a compiled application, that exception is raised when creating the generated class for the page during the initial markup compile.
Adding Elements to Parsed Element Trees
Any additions to the element tree after initial loading and processing must call the appropriate implementation of RegisterName for the class that defines the XAML namescope. Otherwise, the added object cannot be referenced by name through methods such as FindName. Merely setting a Name property (or x:Name Attribute) does not register that name into any XAML namescope. Adding a named element to an element tree that has a XAML namescope also does not register the name to the XAML namescope. Although XAML namescopes can be nested, you generally register names to the XAML namescope that exists on the root element, so that your XAML namescope location parallels the XAML namescope that would have been created in an equivalent loaded XAML page. The most common scenario for application developers is that you will use RegisterName to register names into the XAML namescope on the current root of the page. RegisterName is part of one important scenario for finding storyboards that will run as animations. For more information, see Storyboards Overview. If you call RegisterName on an element other than the root element in the same object tree, the name is still registered to the element nearest the root, as if you had called RegisterName on the root element.
XAML Namescopes in Code
You can create and then use XAML namescopes in code. The APIs in use and the concepts involved are the same even for a pure code usage, because the XAML processor for WPF uses these APIs and concepts when it processes XAML itself, and the concepts and API exist mainly for the purpose of being able to find objects by name within an object tree that is typically defined partially or entirely in XAML.
For applications that are created programmatically, and not from loaded XAML, the root element must implement INameScope, or be a FrameworkElement or FrameworkContentElement derived class, in order to support a XAML namescope.
Also, for any element that is not loaded and processed by a XAML processor, the XAML namescope for the object is not created or initialized by default. You must explicitly create a new XAML namescope for any element that you intend to register names into subsequently. To create a XAML namescope, you call the static SetNameScope method. Specify the object that will own it as the dependencyObject parameter, and a new NameScope constructor call as the value parameter.
If the object provided as dependencyObject for SetNameScope is not a INameScope implementation, FrameworkElement or FrameworkContentElement, then calling RegisterName on any child elements will have no effect. If you fail to create the new XAML namescope explicitly, then calls to RegisterName will raise an exception.
For an example of using XAML namescope APIs in code, see How to: Define a Name Scope.
XAML Namescopes in Styles and Templates
Styles and templates in WPF provide the ability to reuse and reapply content in a straightforward way, but styles and templates might also include elements with names defined at the template level. That same template might be used multiple times in a page. For this reason, styles and templates both define their own XAML namescopes, independent of the containing page where the style or template is applied.
Consider the following example:
<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>
Here, the same template is applied to two different buttons. If templates did not have discrete XAML namescopes, the TheBorder name used in the template would cause a name collision. Each instantiation of the template has its own XAML namescope, so in this example each instantiated template's XAML namescope would contain exactly one name.
Styles also define their own XAML namescope, mostly so that parts of storyboards can have particular names assigned. These names enable control specific behaviors that will target elements of that name, even if the template was re-defined as part of control customization.
Because of the separate XAML namescopes, finding named elements in a template is more challenging than finding a non-templated named element in a page. You first need to determine the applied template, by getting the Template property value of the control where the template is applied. Then, you call the template version of FindName, passing the control where the template was applied as the second parameter.
If you are a control author and you are generating a convention where a particular named element in an applied template is the target for a behavior that is defined by the control itself, you can use the GetTemplateChild method from your control implementation code. The GetTemplateChild method is protected, so only the control author has access to it.
If you are working from within a template, and need to get to the XAML namescope where the template is applied, get the value of TemplatedParent, and then call FindName there. An example of working within the template would be if you are writing the event handler implementation where the event will be raised from an element in an applied template.
XAML Namescopes and Name-related APIs
FrameworkElement has FindName, RegisterName and UnregisterName methods. If the object you call these methods on owns a XAML namescope, the methods call into the methods of the relevant XAML namescope. Otherwise, the parent element is checked to see if it owns a XAML namescope, and this process continues recursively until a XAML namescope is found (because of the XAML processor behavior, there is guaranteed to be a XAML namescope at the root). FrameworkContentElement has analogous behaviors, with the exception that no FrameworkContentElement will ever own a XAML namescope. The methods exist on FrameworkContentElement so that the calls can be forwarded eventually to a FrameworkElement parent element.
SetNameScope is used to map a new XAML namescope to an existing object. You can call SetNameScope more than once in order to reset or clear the XAML namescope, but that is not a common usage. Also, GetNameScope is not typically used from code.
XAML Namescope Implementations
The following classes implement INameScope directly:
ResourceDictionary does not use XAML names or namescopes ; it uses keys instead, because it is a dictionary implementation. The only reason that ResourceDictionary implements INameScope is so it can raise exceptions to user code that help clarify the distinction between a true XAML namescope and how a ResourceDictionary handles keys, and also to assure that XAML namescopes are not applied to a ResourceDictionary by parent elements.
FrameworkTemplate and Style implement INameScope through explicit interface definitions. The explicit implementations allow these XAML namescopes to behave conventionally when they are accessed through the INameScope interface, which is how XAML namescopes are communicated by WPF internal processes. But the explicit interface definitions are not part of the conventional API surface of FrameworkTemplate and Style, because you seldom need to call the INameScope methods on FrameworkTemplate and Style directly, and instead would use other API such as GetTemplateChild.
The following classes define their own XAML namescope, by using the System.Windows.NameScope helper class and connecting to its XAML namescope implementation through the NameScope.NameScope attached property:
See Also
Concepts
XAML Namespaces and Namespace Mapping
Reference
Change History
Date |
History |
Reason |
---|---|---|
August 2008 |
Customer feedback requested adding orientation for "namescope" concepts in general. Added a definition, and this topic now focuses on explaining how XAML namescopes are a specific implementation of a broader and more generic "namescope" concept. |
Information enhancement. |