Wpf - Extensiones de marcado

Descripción general

Las extensiones de marcado son una forma de obtener un valor que no sea específico de tipo primitivo o un objeto XAML. Se puede implementar una extensión de marcado para que proporcione valores para las propiedades de un uso de atributo, las propiedades de un uso de elemento de propiedad o ambas.

[TOC] Tabla de Contenidos

Cuando se utiliza para proporcionar un valor de atributo, la sintaxis que distingue una secuencia de extensión de marcado de un procesador de XAML es la presencia de llaves de apertura y cierre ({ y }). El token de cadena que sigue inmediatamente a la llave de apertura identifica el tipo de extensión de marcado.

Existen extensiones de marcados muy usadas y conocidas como Binding o StaticResource. Pero… ¿conoces todas las extensiones disponibles y su uso?.

En este artículo, vamos a conocer todas las extensiones básicas existentes.


↑↑↑

Extensiones de marcado definidas por XAML

Existen varias extensiones de marcado que no son específicas de la implementación WPF de XAML, sino que son implementaciones de elementos intrínsecos o características del XAML como lenguaje. Estas extensiones de marcado se implementan en el ensamblado System.Xaml como parte de los servicios generales XAML de .NET Framework y están dentro del espacio de nombres XAML del lenguaje XAML. Por lo que se refiere al uso de marcado común, estas extensiones de marcado son típicamente identificables por el prefijo x:. La clase base MarkupExtension (también definida en System.Xaml) proporciona el modelo que todas las extensiones de marcado deben utilizar para ser compatibles con los lectores y sistemas de escritura XAML, incluido XAML de WPF.


↑↑↑

Atributo x:Class

Configura la compilación de XAML para unir clases parciales entre el marcado y el código subyacente. La clase parcial de código se define en un archivo de código separado y la clase parcial de marcado se crea mediante la generación del código durante la compilación de XAML.

        
            <object x:Class="namespace.classname"...>
              ...
            </object>
            <Window x:Class="MainWindow">
                <Grid>
                     . . .
                </Grid>
            </Window>
        

El valor del atributo x:Class debe ser una cadena que especifique el nombre completo de una clase. Puedes omitir la información del espacio de nombres si esa es también la forma en que se estructura el código subyacente. Mas información sobre el atributo x:Class


↑↑↑

Atributo x:ClassModifier

Modifica el comportamiento de la compilación de XAML. Permite cambiar el calificador de acceso de una de un a ventana o un control

            <UserControl x:Class="Uc_TreeViewDirectory" x:ClassModifier="Friend" />
        

Otro estudio sobre el Atributo x:ClassModifier


↑↑↑

Atributo x:FieldModifier

Modifica el comportamiento de la compilación de XAML. Permite cambiar el calificador de acceso de un control hijo

            
           <Grid x:Name="nombreParaEsteControlGrid" x:FieldModifier="Private">
               (etc)
               (etc)
           </Grid>
         

¡ ATENCION ! El atributo x:Name también debe proporcionarse en el mismo elemento.

El valor del atributo x:FieldModifier variará según el lenguaje de programación. Los valores válidos son private, public, protected, internal o friend. En el caso de C#, Microsoft Visual Basic o las extensiones de componentes de Visual C++ (C++/CX), puedes proporcionar el valor de cadena "public" o "Public"; recuerda que el analizador no fuerza la coincidencia de mayúsculas y minúsculas en este valor de atributo.

El acceso Private es el valor predeterminado.

x:FieldModifier solo es relevante para elementos con el atributo x:Name, ya que ese nombre se usa para hacer referencia al campo una vez que se hace público. Mas información sobre el atributo x:FieldModifier


↑↑↑

Atributo x:Key

Identifica exclusivamente los elementos que se crean y a los cuales se hace referencia como recursos, y que existen dentro de un ResourceDictionary.

   
           <ResourceDictionary>
              <object x:Key="stringKeyValue" />
           </ResourceDictionary>

            <Window.Resources>
                <local:TiempoModeloVista x:Key="TiempoModeloVistaResources" />
            </Window.Resources>      

        

Los elementos secundarios de un ResourceDictionary generalmente incluyen un atributo x:Key que especifica un valor de clave único dentro de ese diccionario. El procesador XAML hace cumplir la exclusividad de la clave en tiempo de carga.

Los valores x:Key que no son únicos generarán errores o excepciones en el analizador.

x:Key y x:Name no son conceptos idénticos. x:Key se usa exclusivamente en los diccionarios de recursos. x:Name se usa para todas las áreas de XAML. Una llamada a FindName mediante el valor de clave no recuperará un recurso con clave. Es posible que los objetos definidos en un diccionario de recursos tengan el elemento x:Key, x:Name o ambos. No es necesario que la clave y el nombre coincidan. Mas información sobre el atributo Atributo x:Key


↑↑↑

Atributo x:Load

Puede utilizar x:Load para optimizar el inicio, la creación del árbol visual y uso de la memoria de su aplicación XAML. Utilizando x:Load tiene un efecto visual similar a la Visibility, excepto que cuando el elemento no se carga, su memoria se libera y internamente un pequeño marcador de posición se utiliza para marcar su lugar en el árbol visual.

El elemento de interfaz de usuario atribuido con x:Load puede ser cargado y descargado a través de código o usando una expresión x:Bind. Esto es útil para reducir los costos de los elementos que se presentan con poca frecuencia o condicional.

Cuando usas x:Load en un contenedor como rejilla o StackPanel, el contenedor y todos sus hijos son cargados o descargados como un grupo. Mas información sobre el atributo Atributo x:Load

        <StackPanel>
           <Grid x:Name="DeferredGrid" x:Load="False">
                    ...
           </Grid>
         </StackPanel>
     

↑↑↑

Atributo x:Name

Identifica de forma única elementos de objeto para acceder al objeto con instancia desde el código subyacente o el código general. Una vez aplicado a un modelo de programación de respaldo, se puede considerar que x:Name es equivalente a la variable que contiene una referencia de objeto, tal como la devuelve un constructor. Mas información sobre el atributo Atributo x:Name


↑↑↑

Atributo x:DeferLoadStrategy

x:DeferLoadStrategy="Lazy", se retrasa la creación de un elemento y sus elementos secundarios consiguiendo así reducir el tiempo de inicio y el coste de la memoria, ya que no es necesario crear los elementos. Esto es útil para reducir los costes de los elementos que no se usan a menudo. El elemento se ejecutará en el momento en que se le haga referencia desde el código o desde VisualStateManager. Mas información sobre el atributo Atributo x:DeferLoadStrategy

        <Grid x:Name="DeferredGrid" x:DeferLoadStrategy="Lazy">
            <Grid.RowDefinitions>
            </Grid.RowDefinitions>
            <Rectangle Height="100" Width="100" Fill="#F65314" Margin="0,0,4,4" />
        </Grid>
        <Button x:Name="RealizeElements" Content="Realize Elements" Click="RealizeElements_Click" />

        private void RealizeElements_Click(object sender, RoutedEventArgs e)
           {
               this.FindName("DeferredGrid"); // This will realize the deferred grid
           }
       

↑↑↑

Atributo x:Phase

Usa x:Phase con la extensión de marcado {x:Bind} para representar los elementos ListView y GridView de forma incremental y mejorar la experiencia de movimiento panorámica. x:Phase proporciona una manera declarativa de lograr el mismo efecto que si se usase el evento ContainerContentChanging para controlar manualmente la representación de los elementos de lista. Mas información sobre el atributo Atributo x:Phase


↑↑↑

Directiva x:Uid

Proporciona un identificador único para los elementos de marcado.

Mas información sobre el atributo Atributo x:Uid

Usa x:Uid para identificar un elemento de objeto en tu código XAML. Este elemento de objeto suele ser una instancia de una clase de control u otro elemento mostrado en una interfaz de usuario. La relación entre la cadena que usas en x:Uid y las cadenas que usas en un archivo de recursos es que las cadenas del archivo de recursos son x:Uid seguida de un punto (.) y, a continuación, seguida del nombre de una propiedad específica del elemento que se está localizando.

↑↑↑

x:Type

Permite establecer el tipo del objeto utilizando {x:Type Class}.

Tiene una función similar al operador typeof() en C# o el operador GetType en Microsoft Visual Basic.

Proporciona el objeto Type para el tipo nombrado.

Esta capacidad se utiliza con más frecuencia en estilos y plantillas.

Para obtener información detallada, vea x:Type. (Extensión de marcado).

En este apunte se muestra el código (xaml) necesario para cargar en un control ListBox la enumeración [DragDropEffects]

<Window x:Class="SampleDragDrop.Window2"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:sys="clr-namespace:System;assembly=mscorlib"
 
        <Window.Resources>
        <ObjectDataProvider MethodName="GetValues"
                            ObjectType="{x:Type sys:Enum}"
                            x:Key="DragProvider">
            <ObjectDataProvider.MethodParameters>
                <x:Type TypeName="DragDropEffects" />
            </ObjectDataProvider.MethodParameters>
        </ObjectDataProvider>
        
      </Window.Resources>
 
    <Grid>
        <ListBox Height="194" 
                 Width="190"
                 HorizontalAlignment="Left"
                 VerticalAlignment="Top"   
        ItemsSource="{Binding Source={StaticResource DragProvider}}"/>
    </Grid>
</Window>

↑↑↑

x:Static

Genera valores estáticos. Los valores provienen de entidades de código de tipo de valor que no son directamente el tipo de un valor de una propiedad de destino, pero se pueden evaluar como ese tipo.

A pesar de lo que pueda dar a pensar, x:Static y StaticResource NO son iguales. Mientras que StaticResource nos permite acceder a un objeto definido en un diccionario de recursos, x:Static nos permite el acceso a una propiedad o constante estática.

<Label 
     Text="Awesome!"
     TextColor="{x:Static Color.Blue}" />

NOTA: Esta extensión de marcado es más potente de lo que pueda parecer. También puedes acceder a campos o propiedades estáticas de tu propio código. Si se cuenta con una clase estática con constantes, se podrían utilizar.

Para obtener información detallada, vea Extensiones de marcado x:Static.


↑↑↑

x:Null

Extensión de marcado que permite establecer valor nulo. {null] como un valor de una propiedad y se puede utilizar para atributos o valores de elemento de propiedad.

Si una propiedad cuenta con soporte a valores no nulos y se desea establecer por defecto a nulo, {x:Null} es la extensión de marcado idónea.

Para obtener información detallada, vea x:Null. (Extensión de marcado)


↑↑↑

x:Array

Proporciona compatibilidad para la creación de matrices generales en la sintaxis de XAML, para aquellos casos en los que la compatibilidad de colección proporcionada por los elementos base y los modelos de control de WPF no se utilizan deliberadamente.

Se pueden definir arrays directamente en XAML gracias a esta extensión de marcado.

<x:Array x:Key="StringArray" Type="{x:Type x:String}">
     <x:String>Hello</x:String>
     <x:String>World</x:String>
</x:Array>

Para obtener información detallada, vea x:Array. (Extensión de marcado).


↑↑↑

Extensiones de marcado específicas de WPF

Las extensiones de marcado más comunes utilizadas en la programación de WPF son las que admiten referencias de recursos (StaticResource y DynamicResource) y las que admiten el enlace de datos (Binding).


↑↑↑

StaticResource

Proporciona un valor para una propiedad sustituyendo su valor por el de un recurso ya definido. Una evaluación de StaticResource se realiza finalmente en tiempo de carga de XAML y no tiene acceso al gráfico de objetos en tiempo de ejecución.

En cada elemento visual podemos definir un conjunto de recursos. Utilizamos ResourceDictionary para a gestión de recursos. Con StaticResource podemos acceder a objetos estáticos definidos como recursos y disponibles en tiempo de compilación.

<ContentPage.Resources>
 <ResourceDictionary>

     <Style x:Key="ErrorLabelStyle" TargetType="Label">
          <Setter Property="TextColor" Value="Red" />
     </Style>

</ResourceDictionary>
</ContentPage.Resources>

<Label Text="Hello!" Style="{StaticResource ErrorLabelStyle}" />

Para obtener información detallada, vea Extensión de marcado StaticResource.


↑↑↑

DynamicResource

Proporciona un valor para una propiedad aplazando ese valor para que sea una referencia a un recurso en tiempo de ejecución. Una referencia de recurso dinámico fuerza una nueva búsqueda cada vez que se obtiene acceso a este tipo de recurso y tiene acceso en tiempo de ejecución al gráfico de objetos.

Es decir, si un recurso es eliminado / añadido en un diccionario de recursos en tiempo de ejecución, DynamicResource permite acceder a él sin problemas

Con el fin de obtener este acceso, el concepto DynamicResource lo admiten las propiedades de dependencia del sistema de propiedades de WPF, y las expresiones evaluadas. Por consiguiente, solo puede usar DynamicResource para un destino de la propiedad de dependencia.

Para obtener información detallada, vea Extensión de marcado DynamicResource.

Esta extensión de marcado es sumamente similar a la anterior pero cuenta con una gran diferencia. DynamicResource permite acceder a recursos añadidos en tiempo de ejecución. Es decir, si un recurso es eliminado / añadido en un diccionario de recursos en tiempo de ejecución, DynamicResource es tu extensión.

var errorLabelStyle = new Style(typeof(Label));

errorLabelStyle.Setters.Add(new Setter() 
{ 
     Property = Label.BackgroundColorProperty, Value = Color.Red 
});

this.Resources.Add(errorLabelStyle);

Tras añadir dinámicament el tiempo de ejecución el estilo, accedemos al mismo:

<Label Text="Hello!" Style="{DynamicResource ErrorLabelStyle}" />

↑↑↑

Extensión de marcado {x:Bind}

La extensión de marcado {x:Bind} (nueva para Windows 10) es una alternativa a {Binding}. {x:Bind} carece de algunas de las características de {Binding}, pero se ejecuta en menos tiempo y usa menos memoria que {Binding} y admite una depuración mejor. Mas información sobre {x:Bind}


        <DataTemplate x:DataType="local:ColorEntry">
           <Grid Background="{x:Bind Brushify(Color)}" Width="240">
              <TextBlock Text="{x:Bind ColorName}" Foreground="{x:Bind TextColor(Color)}" Margin="10,5" />
           </Grid>
        </DataTemplate>



        class ColorEntry
        {
             public string ColorName { get; set; }
             public Color Color { get; set; }
     
             public static SolidColorBrush Brushify(Color c)
             {
                  return new SolidColorBrush(c);
             }
     
             public static SolidColorBrush TextColor(Color c)
             {
                   return new SolidColorBrush(((c.R * 0.299 + c.G * 0.587 + c.B * 0.114) > 150) ? Colors.Black : Colors.White);
             }
        }



        <Page x:Class="QuizGame.View.HostView" ...=...>
            <Button Content="{x:Bind Path=ViewModel.NextButtonText, Mode=OneWay}" ...=... />
        </Page>


        <DataTemplate x:Key="SimpleItemTemplate" x:DataType="data:SampleDataGroup">
            <StackPanel Orientation="Vertical" Height="50">
                <TextBlock Text="{x:Bind Title}" />
               <TextBlock Text="{x:Bind Description}" />
             </StackPanel>
        </DataTemplate>

↑↑↑

Binding

Proporciona un valor enlazado a datos para una propiedad, utilizando el contexto de datos que se aplica al objeto primario en tiempo de ejecución. Esta extensión de marcado es relativamente compleja, porque habilita una sintaxis fundamentalmente incluida en el propio código para especificar un enlace de datos. Para obtener información detallada, vea Enlazar extensión de marcado.

Estamos ante la expresión de marcado más utilizada. Cuando el código XAML se encuentra con un literal entre llaves, lo interpreta y no se limita a mostrarlo como si fuera un simple texto. En este caso hace una evaluación encontrando la palabra reservada Binding, lo que indica que debe enlazar el valor de una propiedad. Pero…¿cómo sabe dónde se encuentra la propiedad?, todos los elementos que componen la interfaz de usuario descienden de una importante jerarquía de clases base que otorgan funcionalidad vital.

Contamos con la propiedad BindingContext que actúa como contexto de datos del elemento. Si la propiedad fuese nula en el elemento, se buscaría de forma ascendente en la jerarquía de elementos. Es decir, si la propiedad BindingContext del elemento visual es nula, buscará en el elemento padre inmediato, etc.

Veamos un ejemplo.

public class Person
{
     public string Name { get; set; }
     public string SurName { get; set; }
}

Establecemos el BindingContext:

BindingContext = person;

A la hora de utilizar el Binding:

<Label Text={Binding Name}" />

En un enlace a datos, la palabra reservada Mode indica la forma en la que se comporta el mismo. Contamos con los siguientes modos:

<Entry Text={Binding Username, Mode=TwoWay}" />

Por otro lado, en ocasiones, lo que se desea mostrar en la interfaz de usuario no equivale al valor enlazado. Podríamos extender modelos añadiendo más propiedades para este propósito, pero no es lo ideal. Para solventar este problema contamos con las propiedades de formateo de texto.

<Label Text="{Binding Count, StringFormat='Number of Records = {0:N}'}" />

Veamos otro ejemplo:

<Label Text="{Binding Date, StringFormat='{0:dd MM yyyy}'}" />

↑↑↑

RelativeSource

Proporciona información de origen para un objeto Binding que puede navegar por varias posibles relaciones en el árbol de objetos en tiempo de ejecución. Esto proporciona una fuente especializada para los enlaces que se crean en plantillas de uso múltiple o se crean en código sin conocimiento completo del árbol de objetos circundante. Para obtener información detallada, vea Extensión de marcado RelativeSource.


↑↑↑

TemplateBinding

Permite que una plantilla de control utilice valores para propiedades con plantilla procedentes de propiedades definidas por el modelo de objetos de la clase que utilizará la plantilla. En otras palabras, la propiedad incluida en la definición de la plantilla puede tener acceso a un contexto que solo exista una vez aplicada la plantilla. Para obtener información detallada, vea Extensión de marcado TemplateBinding. Para obtener más información sobre el uso práctico de TemplateBinding, vea Styling with ControlTemplates Sample.

Un TemplateBinding es similar a un Binding, excepto que el origen de un TemplateBinding siempre se establece automáticamente en el padre de la vista de destino que posee la plantilla de control.

<ControlTemplate x:Key="PageTemplate">
     <StackLayout>
          <Label Text="{TemplateBinding BindingContext.HeaderText}" /> 
          <ContentPresenter />
     </StackLayout>
</ControlTemplate>

↑↑↑

ColorConvertedBitmap

Admite un escenario de creación de imágenes relativamente avanzado. Para obtener información detallada, vea Extensión de marcado ColorConvertedBitmap.


↑↑↑

ComponentResourceKey y ThemeDictionary

Admiten aspectos de la búsqueda de recursos, en concreto para los recursos y temas que se empaquetan con controles personalizados. Para obtener más información, vea Extensión de marcado ComponentResourceKey. , Extensión de marcado ThemeDictionary o Información general sobre la creación de controles.


↑↑↑

Converters

En ocasiones, el valor enlazado no es el deseado. Por ejemplo, tenemos enlazado un valor de tipo DateTime pero deseamos mostrar una cadena de texto al usuario con un formato de fecha aplicado. Justo para este objetivo, tenemos los TypeConverters.

En lugar de extender nuestros modelos con más y más valores, los Converters nos permiten transformar unos valores a otros directamente desde XAML.

<Label Text="{Binding Date}" />

En este caso veríamos el resultado de lanzar el método ToString del DateTime. Podemos crear un Converter:

public class DatetimeToStringConverter : IValueConverter
{
     public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
     {
          if (value == null)
               return string.Empty;

          var datetime = (DateTime)value;
          return datetime.ToLocalTime().ToString("g");
     }

     public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
     {
          throw new NotImplementedException(); 
     }
}

Un Converter es una clase que herede de la interfaz IValueConverter, se implementa el método Convert y ConvertBack. Para utilizar el converter se debe definir primero como recurso:

<ResourceDictionary>
 <local:DatetimeToStringConverter x:Key="DateTimeConverter" />
</ResourceDictionary>

Y posteriormente, utilizar la palabra reservada Converter para acceder al mismo:

<Label Text="{Binding Date, Converter={StaticResource DateTimeConverter}}" />

NOTA: Se suelen utilizar los Converters para transformaciones más complejas.


↑↑↑


↑↑↑

A.2.Enlaces

[Para saber mas]
[Grupo de documentos]
[Documento Index]
[Documento Start]
[Imprimir el Documento]
© 1997 - - La Güeb de Joaquín
Joaquín Medina Serrano
Ésta página es española

Codificación
Fecha de creación 2017-08-22T09:22:36Z
Última actualización
[HTML5 Desarrollado usando CSS3]