Export (0) Print
Expand All

WPF Namescopes

Namescopes are both a concept, and also the programming objects that store relationships between the XAML defined names of objects and their instance equivalents. Namescopes in the WPF managed code are created while loading the pages for a XAML application. 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

Namescopes are created on the root element for a XAML page when the page is loaded. Each name specified within the page is added to a pertinent namescope. Elements that are common root elements (such as Page, and Window) always control a namescope. If an element such as FrameworkElement or FrameworkContentElement is the root element of the page in markup, a XAML loader adds a Page root implicitly.

If you try to use the same name twice in any namescope, an exception will be raised. For a parsed XAML application, that exception is raised when creating the generated class for the loaded page.

Adding Elements to Parsed Element Trees

Any additions to the element tree after loading and processing must call the appropriate implementation of RegisterName for the class that defines the 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 namescope. Adding a named element to an element tree that has a namescope also does not register the name to the namescope. Although namescopes can be nested, you generally register names to the namescope that exists on the root element, so that your namescope location parallels the 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 namescope on the current root. 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 logical tree, the name is still registered to the rootmost element, as if you had called RegisterName on the root element.

Namescopes in Code

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 namescope.

Also, for any element that is not loaded and processed by a XAML loader, the namescope for the object is not created or initialized by default. You must explicitly create a new namescope for any element that you intend to register names into subsequently. To create a namescope for an element, you call the static SetNameScope method. Specify the element 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 namescope explicitly, then calls to RegisterName will raise an exception.

For an example of using namescope APIs in code, see How to: Define a Name Scope.

Namescopes in Styles and Templates

Styles and templates in WPF provide the ability to reuse and reapply content in a straightforward way, but this introduces the complexity that styles and templates might also include elements with names. That same template might be used multiple times in a page. For this reason, styles and templates both define their own namescopes, independent of the containing page where the style or template is applied.

Consider the following example:

<Page
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://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 namescopes, the TheBorder name used in the template would cause a name collision. Each instantiation of the template has its own namescope, so in this example each instantiated template's namescope would contain exactly one name.

Styles also get their own 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 namescopes, finding named elements in a templates is more challenging. You first need to get 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.

If you are working from within a template, and need to get to the namescope where the template is applied, get 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.

Namescopes and Name-related APIs

FrameworkElement has FindName, RegisterName and UnregisterName methods. If the element you call these methods on owns a namescope, the element methods simply call into the namescope methods. Otherwise, the parent element is checked to see if it owns a namescope, and this process continues recursively until a namescope is found (with one guaranteed to be at the root). FrameworkContentElement has analogous behaviors, with the exception that no FrameworkContentElement will ever own a 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 namescope to an existing object. You can call SetNameScope more than once in order to reset or clear the namescope, but that is not a common usage. Also, GetNameScope is not typically used from code.

Namescope Implementations

The following classes implement INameScope directly:

NameScope

Style

ResourceDictionary

FrameworkTemplate

ResourceDictionary does not use namescopes; it uses keys instead, because it is a dictionary/hashtable implementation. The only reason that ResourceDictionary implements INameScope is so it can raise exceptions to help clarify the distinction between a true namescope and how a ResourceDictionary handles keys, and also to assure that namescopes are particularly not applied to a ResourceDictionary by parent elements.

FrameworkTemplate and Style implement INameScope through explicit interface definitions. The explicit implementations allow these namescopes to behave conventionally when they are accessed through the INameScope interface, which is how namescopes are communicated by WPF internal processes. But the explicit interface definitions are not part of the conventional namespace of FrameworkTemplate and Style, because you seldom need to call the INameScope methods on FrameworkTemplate and Style directly.

The following classes define their own namescope, by using the System.Windows.NameScope helper class and connecting to its namescope implementation through the NameScope attached property:

FrameworkElement

FrameworkContentElement

See Also

Community Additions

ADD
Show:
© 2014 Microsoft