Ámbitos de nombres XAMLXAML namescopes

Un ámbito de nombres XAML almacena relaciones entre los nombres de objetos definidos en XAML y sus equivalentes de instancia.A XAML namescope stores relationships between the XAML-defined names of objects and their instance equivalents. Este concepto es similar al significado más amplio del término ámbito de nombres en otras tecnologías y lenguajes de programación.This concept is similar to the wider meaning of the term namescope in other programming languages and technologies.

Cómo se definen los ámbitos de nombres XAMLHow XAML namescopes are defined

Los nombres de los ámbitos de nombres XAML permiten al código de usuario hacer referencia a los objetos que se declararon inicialmente en XAML.Names in XAML namescopes enable user code to reference the objects that were initially declared in XAML. El resultado interno del análisis de XAML es que el tiempo de ejecución crea un conjunto de objetos que conservan algunas o todas las relaciones que esos objetos tenían en las declaraciones XAML.The internal result of parsing XAML is that the runtime creates a set of objects that retain some or all of the relationships these objects had in the XAML declarations. Estas relaciones se mantienen como propiedades de objeto específicas de los objetos creados, o se exponen a los métodos de utilidad en las API del modelo de programación.These relationships are maintained as specific object properties of the created objects, or are exposed to utility methods in the programming model APIs.

El uso más común de un nombre en un ámbito de nombres XAML es como referencia directa a una instancia de objeto, que se habilita en el pase de compilación del marcado como una acción de compilación del proyecto, combinada con un método InitializeComponent generado en las plantillas de clase parcial.The most typical use of a name in a XAML namescope is as a direct reference to an object instance, which is enabled by the markup compile pass as a project build action, combined with a generated InitializeComponent method in the partial class templates.

También puedes usar el método de utilidad FindName en tiempo de ejecución para devolver una referencia a los objetos que se definieron con un nombre en el marcado XAML.You can also use the utility method FindName yourself at run time to return a reference to objects that were defined with a name in the XAML markup.

Más información sobre las acciones de compilación y XAMLMore about build actions and XAML

Técnicamente, lo que sucede es que el código XAML se somete a un pase del compilador de marcado al mismo tiempo que el código XAML y la clase parcial que define para el código subyacente se compilan juntos.What happens technically is that the XAML itself undergoes a markup compiler pass at the same time that the XAML and the partial class it defines for code-behind are compiled together. Cada elemento de objeto con un Name o atributo x:Name definido en el marcado genera un campo interno con un nombre que coincide con el nombre XAML.Each object element with a Name or x:Name attribute defined in the markup generates an internal field with a name that matches the XAML name. Este campo inicialmente está vacío.This field is initially empty. Después, la clase genera un método InitializeComponent que solo se llama cuando todo el código XAML está cargado.Then the class generates an InitializeComponent method that is called only after all the XAML is loaded. Dentro de la lógica de InitializeComponent, cada campo interno se rellena con el valor devuelto FindName para la cadena de nombre equivalente.Within the InitializeComponent logic, each internal field is then populated with the FindName return value for the equivalent name string. Para observar esta infraestructura por ti mismo, examina los archivos ".g" (generados) que se crean para cada página XAML en la subcarpeta /obj de un proyecto de aplicación de Windows Runtime después de la compilación.You can observe this infrastructure for yourself by looking at the ".g" (generated) files that are created for each XAML page in the /obj subfolder of a Windows Runtime app project after compilation. También puedes considerar a los campos y el método InitializeComponent como miembros de los ensamblados resultantes si reflexionas sobre ellos o examinas el contenido del lenguaje de la interfaz.You can also see the fields and InitializeComponent method as members of your resulting assemblies if you reflect over them or otherwise examine their interface language contents.

Nota:    Específicamente para las aplicaciones de Visual C++ extensiones de componentes (C++/CX), no se crea un campo de respaldo para una referencia de x:Name para el elemento raíz de un archivo XAML.Note  Specifically for Visual C++ component extensions (C++/CX) apps, a backing field for an x:Name reference is not created for the root element of a XAML file. Si necesitas hacer referencia al objeto raíz desde el código subyacente en C++/CX, usa otras API o un cruce seguro de árbol.If you need to reference the root object from C++/CX code-behind, use other APIs or tree traversal. Por ejemplo, puedes llamar a FindName para un elemento secundario con nombre conocido y, después, llamar a Parent.For example you can call FindName for a known named child element and then call Parent.

Creación de objetos en tiempo de ejecución con XamlReader.LoadCreating objects at run time with XamlReader.Load

El lenguaje XAML también se puede usar como la entrada de cadena del método XamlReader.Load, que actúa de manera similar a la operación de análisis de origen XAML inicial.XAML can be also be used as the string input for the XamlReader.Load method, which acts analogously to the initial XAML source parse operation. XamlReader.Load crea un nuevo árbol desconectado de objetos en tiempo de ejecución.XamlReader.Load creates a new disconnected tree of objects at run time. Después, el árbol desconectado puede conectarse a algún punto del árbol de objetos principal.The disconnected tree can then be attached to some point on the main object tree. Debes conectar explícitamente el árbol de objetos creado; para ello, agrégalo a una colección de propiedades de contenido como Children, o establece otra propiedad que acepte un valor de objeto (por ejemplo, si cargas un nuevo ImageBrush para un valor de propiedad Fill).You must explicitly connect your created object tree, either by adding it to a content property collection such as Children, or by setting some other property that takes an object value (for example, loading a new ImageBrush for a Fill property value).

Implicaciones del ámbito de nombres XAML de XamlReader.Load XAML namescope implications of XamlReader.Load

El ámbito de nombres XAML preliminar que se define con el nuevo árbol de objetos creado por XamlReader.Load evalúa los nombres definidos en el código XAML proporcionado para comprobar su exclusividad.The preliminary XAML namescope defined by the new object tree created by XamlReader.Load evaluates any defined names in the provided XAML for uniqueness. Si los nombres del código XAML proporcionado no son internamente exclusivos en este punto, XamlReader.Load inicia una excepción.If names in the provided XAML are not internally unique at this point, XamlReader.Load throws an exception. El árbol de objetos desconectado no intenta combinar su ámbito de nombres XAML con el ámbito de nombres XAML de la aplicación principal, si está conectado al árbol de objetos de la aplicación principal.The disconnected object tree does not attempt to merge its XAML namescope with the main application XAML namescope, if or when it is connected to the main application object tree. Después de conectar los árboles, la aplicación contará con un árbol de objetos unificado, pero con ámbitos de nombres XAML discretos en su interior.After you connect the trees, your app has a unified object tree, but that tree has discrete XAML namescopes within it. Las divisiones se producen en los puntos de conexión entre los objetos, donde estableces que alguna propiedad sea el valor devuelto de una llamada XamlReader.Load.The divisions occur at the connection points between objects, where you set some property to be the value returned from a XamlReader.Load call.

El problema de tener ámbitos de nombres XAML discretos y desconectados es que las llamadas al método FindName, así como las referencias a objetos administrados directos, ya no operan con un ámbito de nombres XAML unificado.The complication of having discrete and disconnected XAML namescopes is that calls to the FindName method as well as direct managed object references no longer operate against a unified XAML namescope. En su lugar, el objeto en particular para el que se llama a FindName determina el ámbito, siendo este el ámbito de nombres XAML dentro del cual se encuentra el objeto llamador.Instead, the particular object that FindName is called on implies the scope, with the scope being the XAML namescope that the calling object is within. En el caso de una referencia a objetos administrados directos, el ámbito se determina mediante la clase donde existe el código.In the direct managed object reference case, the scope is implied by the class where the code exists. Por lo general, el código subyacente para la interacción en tiempo de ejecución de una "página" de contenido de la aplicación existe en la clase parcial que respalda la "página" raíz y, por lo tanto, el ámbito de nombres XAML es el ámbito de nombres XAML raíz.Typically, the code-behind for run-time interaction of a "page" of app content exists in the partial class that backs the root "page", and therefore the XAML namescope is the root XAML namescope.

Si llamas a FindName para obtener un objeto con nombre del ámbito de nombres XAML raíz, el método no encontrará los objetos en un ámbito de nombres XAML discreto creado por XamlReader.Load.If you call FindName to get a named object in the root XAML namescope, the method will not find the objects from a discrete XAML namescope created by XamlReader.Load. A la inversa, si llamas a FindName desde un objeto obtenido a partir del ámbito de nombres XAML discreto, el método no encontrará objetos con nombre en el ámbito de nombres XAML raíz.Conversely, if you call FindName from an object obtained from out of the discrete XAML namescope, the method will not find named objects in the root XAML namescope.

Este problema del ámbito de nombres XAML discreto solo afecta a la búsqueda de objetos por nombre en los ámbitos de nombres XAML cuando se usa la llamada FindName.This discrete XAML namescope issue only affects finding objects by name in XAML namescopes when using the FindName call.

Puedes usar varias técnicas para obtener referencias a los objetos definidos en un ámbito de nombres XAML diferente:To get references to objects that are defined in a different XAML namescope, you can use several techniques:

  • Recorra todo el árbol en pasos discretos con propiedades de colección y elementos primarios que se sabe que existen en la estructura de árbol de objetos (por ejemplo, la colección devuelta por panel. Children).Walk the entire tree in discrete steps with Parent and/or collection properties that are known to exist in your object tree structure (such as the collection returned by Panel.Children).
  • Si haces la llamada desde un ámbito de nombres XAML discreto y deseas el ámbito de nombres XAML raíz, siempre es fácil obtener una referencia a la ventana principal que se muestra actualmente.If you are calling from a discrete XAML namescope and want the root XAML namescope, it is always easy to get a reference to the main window currently displayed. Puedes obtener la raíz visual (el elemento XAML raíz, también conocido como origen del contenido) de la ventana de la aplicación actual en una línea de código con la llamada Window.Current.Content.You can get the visual root (the root XAML element, also known as the content source) from the current application window in one line of code with the call Window.Current.Content. Después puedes convertirla a FrameworkElement y llamar a FindName desde este ámbito.You can then cast to FrameworkElement and call FindName from this scope.
  • Si estás llamando desde el ámbito de nombres XAML raíz y deseas un objeto que esté dentro de un ámbito de nombres XAML discreto, lo más conveniente es que planifiques de antemano el código y conserves una referencia al objeto devuelto por XamlReader.Load y agregado al árbol de objetos principal.If you are calling from the root XAML namescope and want an object within a discrete XAML namescope, the best thing to do is to plan ahead in your code and retain a reference to the object that was returned by XamlReader.Load and then added to the main object tree. Este objeto ahora es un objeto válido para llamadas FindName dentro del ámbito de nombres XAML discreto.This object is now a valid object for calling FindName within the discrete XAML namescope. Podrías mantener este objeto disponible como variable global o pasarlo con parámetros del método.You could keep this object available as a global variable or otherwise pass it by using method parameters.
  • Para evitar por completo las consideraciones acerca de los nombres y los ámbitos de nombres XAML, examina el árbol visual.You can avoid names and XAML namescope considerations entirely by examining the visual tree. La API VisualTreeHelper te permite atravesar el árbol visual en términos de objetos principales y colecciones secundarias exclusivamente según la posición y el índice.The VisualTreeHelper API enables you to traverse the visual tree in terms of parent objects and child collections, based purely on position and index.

Ámbitos de nombres XAML en plantillasXAML namescopes in templates

En XAML, las plantillas ofrecen la posibilidad de volver a usar y aplicar contenido de una manera sencilla, pero las plantillas también pueden incluir elementos con nombres definidos en el nivel de plantilla. Templates in XAML provide the ability to reuse and reapply content in a straightforward way, but templates might also include elements with names defined at the template level. Esa misma plantilla se puede usar varias veces en una página.That same template might be used multiple times in a page. Por esta razón, las plantillas definen sus propios ámbitos de nombres XAML sin importar la página contenedora donde se aplica el estilo o la plantilla.For this reason, templates define their own XAML namescopes, independent of the containing page where the style or template is applied. Considere este ejemplo:Consider this 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="MyTemplate">
      ....
      <TextBlock x:Name="MyTextBlock" />
    </ControlTemplate>
  </Page.Resources>
  <StackPanel>
    <SomeControl Template="{StaticResource MyTemplate}" />
    <SomeControl Template="{StaticResource MyTemplate}" />
  </StackPanel>
</Page>

Aquí se aplica la misma plantilla a dos controles diferentes.Here, the same template is applied to two different controls. Si las plantillas no tenían ámbitos de nombres XAML discretos, el nombre "MyTextBlock" que se usó en la plantilla provocaría un conflicto de nombres.If templates did not have discrete XAML namescopes, the "MyTextBlock" name used in the template would cause a name collision. Todas las instancias de la plantilla tienen su propio ámbito de nombres XAML, por lo que, en este ejemplo, el ámbito de nombres XAML de todas las plantillas de instancia contendrían exactamente un nombre.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. Sin embargo, el ámbito de nombres XAML raíz no contiene el nombre de ninguna de las plantillas.However, the root XAML namescope does not contain the name from either template.

Debido a la separación de los ámbitos de nombres XAML, buscar elementos con nombre dentro de una plantilla desde el ámbito de la página donde se aplicó la plantilla requiere una técnica diferente.Because of the separate XAML namescopes, finding named elements within a template from the scope of the page where the template is applied requires a different technique. En lugar de llamar a FindName en algún objeto del árbol de objetos, primero se obtiene el objeto al que se aplicó la plantilla y después se llama a GetTemplateChild.Rather than calling FindName on some object in the object tree, you first obtain the object that has the template applied, and then call GetTemplateChild. Si eres el autor del control y estás generando una convención por la que un determinado elemento con nombre de una plantilla aplicada es el destino para un comportamiento definido por el propio control, puedes usar el método GetTemplateChild desde el código de implementación del control.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. El método GetTemplateChild está protegido, por lo que solo el autor del control tiene acceso a él.The GetTemplateChild method is protected, so only the control author has access to it. Además, existen convenciones que los autores de controles deben seguir para asignar nombres a las partes y a las partes de las plantillas, y notificarlas como valores de atributo que se aplican a la clase del control.Also, there are conventions that control authors should follow in order to name parts and template parts and report these as attribute values applied to the control class. Esta técnica permite que los usuarios del control puedan detectar los nombres de partes importantes; además, es posible que deseen aplicar una plantilla distinta, para lo que sería necesario reemplazar las partes con nombre a fin de mantener la funcionalidad del control.This technique makes the names of important parts discoverable to control users who might wish to apply a different template, which would need to replace the named parts in order to maintain control functionality.