Share via


Ámbitos de nombres de WPF

Actualización: noviembre 2007

Los ámbitos de nombres son al mismo tiempo un concepto y objetos de programación que almacenan relaciones entre los nombres de los objetos definidos en XAML y sus equivalentes de instancia. Los ámbitos de nombres del código administrado de WPF se crean al cargar las páginas para una aplicación XAML. La interfaz INameScope define los ámbitos de nombres como objetos de programación. También los implementa la clase práctica NameScope.

Este tema contiene las secciones siguientes.

  • Ámbitos de nombres en aplicaciones de XAML cargado
  • Ámbitos de nombres en estilos y plantillas
  • Ámbitos de nombres y API relacionadas con nombres
  • Temas relacionados

Ámbitos de nombres en aplicaciones de XAML cargado

Los ámbitos de nombres se crean en el elemento raíz de una página XAML al procesarla. Cada nombre especificado dentro de la página se agrega al ámbito de nombres pertinente. Los elementos que son elementos raíz comunes (como Page y Window) siempre controlan un ámbito de nombres. Si un elemento, como FrameworkElement o FrameworkContentElement, es el elemento raíz de la página en el marcado, un procesador XAML agrega implícitamente una raíz de Page para que Page pueda proporcionar un ámbito de nombres. Se crea un ámbito de nombres aunque no se hay definido ningún atributo Name o x:Name inicialmente en XAML.

Si intenta utilizar dos veces el mismo nombre en un ámbito de nombres, se inicia una excepción. Para el XAML que tiene código subyacente y forma parte de una aplicación compilada, esa excepción se inicia al crear la clase generada para la página.

Agregar elementos a árboles de elementos analizados

Cualquier adición al árbol de elementos después de la carga y el procesamiento iniciales debe llamar a la implementación adecuada de RegisterName para la clase que define el ámbito de nombres. De lo contrario, no se podrá hacer referencia al objeto agregado por su nombre mediante métodos tales como FindName. No basta con establecer una propiedad Name (o un Atributo x:Name) para registrar ese nombre en cualquier ámbito de nombres. Al agregar un elemento con nombre a un árbol de elementos que tiene un ámbito de nombres tampoco se registra el nombre en el ámbito de nombres. Aunque los ámbitos de nombres se pueden anidar, en general los nombres se registran en el ámbito de nombres que existe en el elemento raíz, para que la ubicación del ámbito de nombres creada por usted sea la misma que se habría creado en una página equivalente de XAML cargado. El escenario más común para los programadores de aplicaciones consiste en utilizar RegisterName para registrar los nombres en el ámbito de nombres en la raíz actual. RegisterName forma parte de un escenario importante para buscar guiones gráficos que se ejecutarán como animaciones. Para obtener más información, vea Información general sobre objetos Storyboard. Si llama al método RegisterName para un elemento distinto del elemento raíz en el mismo árbol lógico, el nombre se registrará de todos modos en el elemento más cercano la raíz, como si hubiera llamado a RegisterName en el elemento raíz.

Ámbitos de nombres en código

Para las aplicaciones que se crean mediante programación y no a partir de XAML cargado, el elemento raíz debe implementar INameScope, o ser una clase derivada de FrameworkElement o de FrameworkContentElement, para admitir un ámbito de nombres.

Además, para cualquier elemento que no se cargue y procese mediante un procesador XAML, el ámbito de nombres del objeto no se crea ni inicializa de manera predeterminada. Debe crear de manera explícita un nuevo ámbito de nombres para cualquier elemento en el que vaya a registrar nombres seguidamente. Para crear un ámbito de nombres para un elemento, se llama al método SetNameScope estático. Especifique el elemento como el parámetro dependencyObject y una nueva llamada al constructor NameScope como el parámetro value.

Si el objeto proporcionado como parámetro dependencyObject para el método SetNameScope no es una implementación de INameScope, FrameworkElement o FrameworkContentElement, entonces llamar a RegisterName en cualquier elemento secundario no surtirá ningún efecto. Si no crea explícitamente el nuevo ámbito de nombres, al llamar a RegisterName se iniciará una excepción.

Para obtener un ejemplo del uso de API de ámbito de nombres en código, vea Cómo: Definir un ámbito de nombres.

Ámbitos de nombres en estilos y plantillas

Los estilos y las plantillas de WPF proporcionan la capacidad de reutilizar y aplicar de nuevo el contenido de una manera sencilla, pero los estilos y las plantillas también pueden incluir elementos con nombres definidos en el nivel de plantilla. Esta misma plantilla se puede utilizar varias veces en una página. Por este motivo, los estilos y las plantillas definen sus propios ámbitos de nombres, independientes de la página contenedora donde se aplican dichos estilos y plantillas.

Considere el ejemplo siguiente:

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

Aquí, se aplica la misma plantilla a dos botones diferentes. Si las plantillas no tuvieran el ámbitos de nombres discretos, el nombre TheBorder utilizado en la plantilla provocaría un conflicto de nombres. Cada instancia que se crea de la plantilla tiene su propio ámbito de nombres, por lo que en este ejemplo el ámbito de nombres de cada instancia de la plantilla contendrá exactamente un nombre.

Los estilos también obtienen su propio ámbito de nombres, principalmente para permitir la asignación de nombres concretos a los distintos componentes del guión. Estos nombres habilitan comportamientos concretos destinados a elementos de ese nombre, aunque se vuelva a definir la plantilla como parte de la personalización de un control.

A causa de los ámbitos de nombres independientes, buscar elementos con nombre en una plantilla resulta más complicado que hacerlo en un elemento sin plantilla de una página. En primer lugar, debe determinar cuál es la plantilla aplicada, obteniendo el valor de la propiedad Template del control donde se aplica la plantilla. A continuación, se llama a la versión de plantilla de FindName, y se pasa el control donde se aplicó la plantilla como segundo parámetro.

Si usted es el autor de un control y genera una convención donde un elemento con nombre determinado de una plantilla aplicada es el destino para un comportamiento definido por el propio control, puede utilizar el método GetTemplateChild del código de implementación del control. El método GetTemplateChild se protege, de tal forma que únicamente su autor tiene acceso a él.

Si trabaja desde dentro de una plantilla y necesita obtener el espacio de nombres donde se aplica la plantilla, obtenga TemplatedParent y, a continuación, llame a FindName desde allí. Un ejemplo de trabajo dentro de la plantilla sería escribir la implementación del controlador de eventos donde el evento se provocará desde un elemento de una plantilla aplicada.

Ámbitos de nombres y API relacionadas con nombres

FrameworkElement tiene los métodos FindName, RegisterName y UnregisterName. Si el elemento para el que llama a estos métodos posee un ámbito de nombres, los métodos del elemento se limitan a llamar a los métodos del ámbito de nombres. De lo contrario, se comprueba el elemento primario por si posee un ámbito de nombres, y este proceso continúa de forma recursiva hasta que se encuentra un ámbito de nombres (debido al comportamiento del procesador XAML, es seguro que hay un ámbito de nombres en la raíz). FrameworkContentElement tiene comportamientos análogos, con la excepción de que ningún FrameworkContentElement poseerá jamás un ámbito de nombres. Los métodos existen en FrameworkContentElement para que las llamadas se puedan reenviar, en caso necesario, a un elemento primario FrameworkElement.

SetNameScope se utiliza para asignar un nuevo ámbito de nombres a un objeto existente. Puede llamar más de una vez a SetNameScope a fin de restablecer o borrar el ámbito de nombres, pero no suele hacerse. GetNameScope tampoco se suele utilizar mediante código.

Implementaciones de ámbitos de nombres

Las clases siguientes implementan INameScope directamente:

ResourceDictionary no utiliza ámbitos de nombres, sino claves, porque es una implementación de diccionario-tabla hash. La única razón por la que ResourceDictionary implementa INameScope es para poder iniciar excepciones en el código de usuario que ayuden a aclarar la distinción entre un ámbito de nombres verdadero y la manera de administrar las claves por parte de ResourceDictionary, además de asegurarse, en particular, de que ningún elemento primario aplique ámbitos de nombres a ResourceDictionary.

FrameworkTemplate y Style implementan INameScope mediante definiciones de interfaz explícitas. Las implementaciones explícitas permiten que estos ámbitos de nombres se comporten de un modo convencional cuando se tiene acceso a ellos a través de la interfaz INameScope, que es el modo que los procesos internos de WPF utilizan para comunicar los ámbitos de nombres. No obstante, las definiciones de interfaz explícitas no forman parte de la superficie de API convencional de FrameworkTemplate y Style, porque casi nunca se necesita llamar directamente a los métodos INameScope en FrameworkTemplate y Style.

Las clases siguientes definen su propio ámbito de nombres, utilizando la clase de aplicación auxiliar System.Windows.NameScope y conectándose a su implementación de ámbito de nombres a través de la propiedad asociada NameScope:

Vea también

Conceptos

Espacios de nombres y asignación de espacios de nombres de XAML

Referencia

Atributo x:Name