Información general sobre plantillas de datos

 

Publicado: junio de 2016

El Entity with relative path '../Token/TLA2%23tla_winclient_md.md' can not be found, for source topic '{"project_id":"3fedad16-eaf1-41a6-8f96-0c1949c68f32","entity_id":"0f4d9f8c-0230-4013-bd7b-e8e7fed01b4a","entity_type":"Article","locale":"es-ES"}'. modelo de plantillas de datos proporciona gran flexibilidad para definir la presentación de los datos. Entity with relative path '../Token/TLA2%23tla_winclient_md.md' can not be found, for source topic '{"project_id":"3fedad16-eaf1-41a6-8f96-0c1949c68f32","entity_id":"0f4d9f8c-0230-4013-bd7b-e8e7fed01b4a","entity_type":"Article","locale":"es-ES"}'.los controles tienen funcionalidades integradas para admitir la personalización de la presentación de los datos. Este tema muestra primero cómo definir un DataTemplate y, a continuación, presenta otras características de creación de plantillas de datos, como la selección de plantillas basadas en la lógica personalizada y la compatibilidad con la presentación de datos jerárquicos.

Entity with relative path '../Token/autoOutline_md.md' can not be found, for source topic '{"project_id":"3fedad16-eaf1-41a6-8f96-0c1949c68f32","entity_id":"0f4d9f8c-0230-4013-bd7b-e8e7fed01b4a","entity_type":"Article","locale":"es-ES"}'.

Este tema se centra en las características de creación de plantillas de datos y no es una introducción de los conceptos de enlace de datos. Para obtener información acerca de los conceptos de enlace de datos básicos, consulte la información general sobre el enlace de datos.

DataTemplate es sobre la presentación de datos y es una de las muchas características proporcionadas por el Entity with relative path '../Token/TLA2%23tla_winclient_md.md' can not be found, for source topic '{"project_id":"3fedad16-eaf1-41a6-8f96-0c1949c68f32","entity_id":"0f4d9f8c-0230-4013-bd7b-e8e7fed01b4a","entity_type":"Article","locale":"es-ES"}'. modelo de estilos y plantillas. Para obtener una introducción de la Entity with relative path '../Token/TLA2%23tla_winclient_md.md' can not be found, for source topic '{"project_id":"3fedad16-eaf1-41a6-8f96-0c1949c68f32","entity_id":"0f4d9f8c-0230-4013-bd7b-e8e7fed01b4a","entity_type":"Article","locale":"es-ES"}'. modelo de estilos y plantillas, como el uso de un estilo para establecer propiedades de controles, consulte el estilos y plantillas tema.

Además, es importante comprender Resources, que son esencialmente lo habilite objetos como estilo y DataTemplate sean reutilizables. Para obtener más información sobre recursos, consulte recursos XAML.

Entity with relative path '../Token/autoOutline_md.md' can not be found, for source topic '{"project_id":"3fedad16-eaf1-41a6-8f96-0c1949c68f32","entity_id":"0f4d9f8c-0230-4013-bd7b-e8e7fed01b4a","entity_type":"Article","locale":"es-ES"}'.

Para mostrar por qué DataTemplate es importante, analicemos un ejemplo de enlace de datos. En este ejemplo, tenemos un ListBox que está enlazado a una lista de Task objetos. Cada Task objeto tiene una TaskName (cadena), un Description (cadena), un Priority (int) y una propiedad de tipo TaskType, que es un Enum con valores Home y Work.

<Window x:Class="SDKSample.Window1"
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  xmlns:local="clr-namespace:SDKSample"
  Title="Introduction to Data Templating Sample">
  <Window.Resources>
    <local:Tasks x:Key="myTodoList"/>


</Window.Resources>
  <StackPanel>
    <TextBlock Name="blah" FontSize="20" Text="My Task List:"/>
    <ListBox Width="400" Margin="10"
             ItemsSource="{Binding Source={StaticResource myTodoList}}"/>

  </StackPanel>
</Window>

Sin un DataTemplate

Sin un DataTemplatenuestra ListBox actualmente tiene este aspecto:

Captura de pantalla de ejemplo de datos plantillas

Lo que sucede es que, sin ninguna instrucción concreta, el ListBox por llamadas predeterminado ToString al intentar mostrar los objetos de la colección. Por lo tanto, si la Task objeto invalidaciones la ToString (método), el ListBox muestra la representación de cadena de cada objeto de origen en la colección subyacente.

Por ejemplo, si la Task clase invalidaciones la ToString método de este modo, donde name es el campo para el TaskName propiedad:

      public override string ToString()
      {
          return name.ToString();
      }

La ListBox el siguiente aspecto:

Captura de pantalla de ejemplo de datos plantillas

Sin embargo, eso resulta limitante e inflexible. Además, si va a enlazar a XML datos, no podrá invalidar ToString.

Definir una plantilla de datos Simple

La solución consiste en definir una DataTemplate. Una manera de hacerlo es establecer el ItemTemplate propiedad de la ListBox a una DataTemplate. Lo que especifique en la DataTemplate se convierte en la estructura visual de su objeto de datos. El siguiente DataTemplate es bastante sencillo. Estamos proporcionando instrucciones para que cada elemento aparezca como tres TextBlock elementos dentro de un StackPanel. Cada TextBlock elemento está enlazado a una propiedad de la Task clase.

    <ListBox Width="400" Margin="10"
             ItemsSource="{Binding Source={StaticResource myTodoList}}">
       <ListBox.ItemTemplate>
         <DataTemplate>
           <StackPanel>
             <TextBlock Text="{Binding Path=TaskName}" />
             <TextBlock Text="{Binding Path=Description}"/>
             <TextBlock Text="{Binding Path=Priority}"/>
           </StackPanel>
         </DataTemplate>
       </ListBox.ItemTemplate>
     </ListBox>

Los datos subyacentes de los ejemplos de este tema están una colección de CLR objetos. Si va a enlazar a XML datos, los conceptos fundamentales son los mismos, pero hay una ligera diferencia sintáctica. Por ejemplo, en lugar de tener Path=TaskName, establecería XPath a @TaskName (si TaskName es un atributo de su XML nodo).

Ahora nuestra ListBox el siguiente aspecto:

Captura de pantalla de ejemplo de datos plantillas

Crear la plantilla de datos como un recurso

En el ejemplo anterior, hemos definido la DataTemplate en línea. Es más común para definir en la sección de recursos para que pueda ser un objeto reutilizable, como en el ejemplo siguiente:

  <Window.Resources>

    <DataTemplate x:Key="myTaskTemplate">
      <StackPanel>
        <TextBlock Text="{Binding Path=TaskName}" />
        <TextBlock Text="{Binding Path=Description}"/>
        <TextBlock Text="{Binding Path=Priority}"/>
      </StackPanel>
    </DataTemplate>

</Window.Resources>

Ahora puede usar myTaskTemplate como un recurso, como en el ejemplo siguiente:

    <ListBox Width="400" Margin="10"
             ItemsSource="{Binding Source={StaticResource myTodoList}}"
             ItemTemplate="{StaticResource myTaskTemplate}"/>

Porque myTaskTemplate es un recurso, ahora se puede utilizar en otros controles que tienen una propiedad que toma un DataTemplate tipo. Como se muestra anteriormente, para ItemsControl objetos, como el ListBox, es el ItemTemplate propiedad. Para ContentControl objetos, es el ContentTemplate propiedad.

La propiedad DataType

El DataTemplate clase tiene un DataType propiedad que es muy similar a la TargetType propiedad de la estilo clase. Por lo tanto, en lugar de especificar un x:Key para el DataTemplate en el ejemplo anterior, puede hacer lo siguiente:

    <DataTemplate DataType="{x:Type local:Task}">
      <StackPanel>
        <TextBlock Text="{Binding Path=TaskName}" />
        <TextBlock Text="{Binding Path=Description}"/>
        <TextBlock Text="{Binding Path=Priority}"/>
      </StackPanel>
    </DataTemplate>

Esto DataTemplate se aplica automáticamente a todos los Task objetos. Tenga en cuenta que en este caso el x:Key se establece implícitamente. Por lo tanto, si asigna este DataTemplate una x:Key valor, se va a reemplazar el implícita x:Key y DataTemplate no se aplica automáticamente.

Si está enlazando un ContentControl a una colección de Task objetos, el ContentControl no se utiliza el comando anterior DataTemplate automáticamente. Esto es porque el enlace en un ContentControl necesita más información para distinguir si desea enlazar a una colección completa o a los objetos individuales. Si su ContentControl efectúa el seguimiento de la selección de un ItemsControl tipo, puede establecer la ruta propiedad de la ContentControl enlace a "/" para indicar que le interesa el elemento actual. Para obtener un ejemplo, vea enlazar a una colección y mostrar información basada en la selección. De lo contrario, debe especificar el DataTemplate explícitamente estableciendo la ContentTemplate propiedad.

El DataType propiedad resulta especialmente útil cuando tenga un CompositeCollection de diferentes tipos de objetos de datos. Para obtener un ejemplo, vea implementar una CompositeCollection.

Actualmente, los datos aparecen con la información necesaria, pero está claro que hay espacio para la mejora. Vamos a mejorar la presentación agregando un borde, cuadrículay algunos TextBlock elementos que describen los datos que se va a mostrar.


    <DataTemplate x:Key="myTaskTemplate">
      <Border Name="border" BorderBrush="Aqua" BorderThickness="1"
              Padding="5" Margin="5">
        <Grid>
          <Grid.RowDefinitions>
            <RowDefinition/>
            <RowDefinition/>
            <RowDefinition/>
          </Grid.RowDefinitions>
          <Grid.ColumnDefinitions>
            <ColumnDefinition />
            <ColumnDefinition />
          </Grid.ColumnDefinitions>
          <TextBlock Grid.Row="0" Grid.Column="0" Text="Task Name:"/>
          <TextBlock Grid.Row="0" Grid.Column="1" Text="{Binding Path=TaskName}" />
          <TextBlock Grid.Row="1" Grid.Column="0" Text="Description:"/>
          <TextBlock Grid.Row="1" Grid.Column="1" Text="{Binding Path=Description}"/>
          <TextBlock Grid.Row="2" Grid.Column="0" Text="Priority:"/>
          <TextBlock Grid.Row="2" Grid.Column="1" Text="{Binding Path=Priority}"/>
        </Grid>
      </Border>

    </DataTemplate>

La siguiente captura de pantalla muestra la ListBox con esta modificación DataTemplate:

Captura de pantalla de ejemplo de datos plantillas

Podemos establecer HorizontalContentAlignment a Stretch en el ListBox para asegurarse de que el ancho de los elementos ocupe todo el espacio:

    <ListBox Width="400" Margin="10"
         ItemsSource="{Binding Source={StaticResource myTodoList}}"
         ItemTemplate="{StaticResource myTaskTemplate}" 
         HorizontalContentAlignment="Stretch"/>

Con el HorizontalContentAlignment propiedad establecida en Stretch, ListBox ahora el siguiente aspecto:

Captura de pantalla de ejemplo de datos plantillas

Utilizar DataTriggers para aplicar valores de propiedad

La presentación actual no Díganos si una Task es una tarea de inicio o una tarea de office. Recuerde que la Task objeto tiene una TaskType propiedad de tipo TaskType, que es una enumeración con valores Home y Work.

En el ejemplo siguiente, la DataTrigger establece la BorderBrush del elemento denominado border a Yellow si la TaskType propiedad es TaskType.Home.

    <DataTemplate x:Key="myTaskTemplate">

    <DataTemplate.Triggers>
      <DataTrigger Binding="{Binding Path=TaskType}">
        <DataTrigger.Value>
          <local:TaskType>Home</local:TaskType>
        </DataTrigger.Value>
        <Setter TargetName="border" Property="BorderBrush" Value="Yellow"/>
      </DataTrigger>
    </DataTemplate.Triggers>

    </DataTemplate>

Ahora, nuestra aplicación tiene el siguiente aspecto. Las tareas domésticas aparecerán con un borde amarillo y las tareas de office con un borde aguamarina:

Captura de pantalla de ejemplo de datos plantillas

En este ejemplo el DataTrigger utiliza un establecedor para establecer un valor de propiedad. Las clases de desencadenador también tienen la EnterActions y ExitActions propiedades que permiten iniciar un conjunto de acciones tales como animaciones. Además, también hay un MultiDataTrigger clase que permite aplicar los cambios se basa en varios valores de la propiedad enlazada a datos.

Una manera alternativa de lograr el mismo efecto es enlazar la BorderBrush propiedad a la TaskType propiedad y use un convertidor de valores para devolver el color según el TaskType valor. Creación del efecto anterior mediante un convertidor es ligeramente más eficaz en términos de rendimiento. Además, crear su propio convertidor ofrece más flexibilidad porque está proporcionando su propia lógica. En última instancia, la técnica que elija depende de su escenario y de sus preferencias. Para obtener información sobre cómo escribir un convertidor, vea IValueConverter.

¿Cuáles son los de una plantilla de datos?

En el ejemplo anterior, colocamos el desencadenador dentro de la DataTemplate utilizando la DataTemplate. Desencadenadores propiedad. El establecedor del desencadenador establece el valor de una propiedad de un elemento (la borde elemento) que está dentro de la DataTemplate. Sin embargo, si las propiedades que su Setters les preocupa no son propiedades de elementos que están dentro del actual DataTemplate, puede ser más adecuado establecer las propiedades mediante un estilo para el ListBoxItem clase (si es el control que se va a enlazar una ListBox). Por ejemplo, si desea que su desencadenador para animar el opacidad valor del elemento cuando un mouse apunta a un elemento, defina desencadenadores dentro de un ListBoxItem estilo. Para obtener un ejemplo, consulte el Introducción al ejemplo de plantillas y estilos.

En general, tenga en cuenta que el DataTemplate se aplica a cada uno de los nodos ListBoxItem (para obtener más información acerca de cómo y dónde se aplica realmente, vea la ItemTemplate página.). La DataTemplate está relacionado con solo la presentación y la apariencia de los objetos de datos. En la mayoría de los casos, todos los demás aspectos de presentación, como un elemento de qué aspecto cuando se selecciona o cómo la ListBox establece los elementos no pertenecen a la definición de un DataTemplate. Para obtener un ejemplo, consulte el estilos y plantillas para ItemsControl sección.

En la propiedad DataType sección, explicamos que puede definir diferentes plantillas de datos para objetos de datos diferentes. Esto es especialmente útil cuando tenga un CompositeCollection de diferentes tipos o colecciones con elementos de diferentes tipos. En el Utilizar DataTriggers para aplicar valores de propiedad sección, hemos mostrado que si tiene una colección del mismo tipo de objetos de datos puede crear un DataTemplate y, a continuación, utilizar desencadenadores para aplicar cambios en función de los valores de propiedad de cada objeto de datos. Sin embargo, los desencadenadores permiten aplicar valores de propiedad o iniciar animaciones, pero no ofrecen la flexibilidad necesaria para reconstruir la estructura de los objetos de datos. Algunos escenarios pueden requerir crear otro DataTemplate para datos de objetos que son del mismo tipo pero tienen propiedades diferentes.

Por ejemplo, cuando un Task objeto tiene una Priority valor de 1, puede darle un aspecto completamente diferente para actuar como una alerta para usted. En ese caso, cree una DataTemplate para la presentación de alta prioridad Task objetos. Vamos a agregar la siguiente DataTemplate a la sección de recursos:

    <DataTemplate x:Key="importantTaskTemplate">
      <DataTemplate.Resources>
        <Style TargetType="TextBlock">
          <Setter Property="FontSize" Value="20"/>
        </Style>
      </DataTemplate.Resources>
      <Border Name="border" BorderBrush="Red" BorderThickness="1"
              Padding="5" Margin="5">
        <DockPanel HorizontalAlignment="Center">
          <TextBlock Text="{Binding Path=Description}" />
          <TextBlock>!</TextBlock>
        </DockPanel>
      </Border>
    </DataTemplate>

Observe que este ejemplo se utiliza la DataTemplate. Recursos propiedad. Recursos definidos en esa sección son compartidos por los elementos dentro de la DataTemplate.

Para proporcionar la lógica para elegir qué DataTemplate utilizar basándose en la Priority valor del objeto de datos, crear una subclase de DataTemplateSelector e invalidar la SelectTemplate método. En el ejemplo siguiente, la SelectTemplate método proporciona la lógica para devolver la plantilla adecuada en función del valor de la Priority propiedad. La plantilla que se devuelve se encuentra en los recursos de la envoltura ventana elemento.

using System.Windows;
using System.Windows.Controls;

namespace SDKSample
{
    public class TaskListDataTemplateSelector : DataTemplateSelector
    {
        public override DataTemplate
            SelectTemplate(object item, DependencyObject container)
        {
            FrameworkElement element = container as FrameworkElement;

            if (element != null && item != null && item is Task)
            {
                Task taskitem = item as Task;

                if (taskitem.Priority == 1)
                    return
                        element.FindResource("importantTaskTemplate") as DataTemplate;
                else
                    return
                        element.FindResource("myTaskTemplate") as DataTemplate;
            }

            return null;
        }
    }
}

Podemos declarar entonces el TaskListDataTemplateSelector como un recurso:

  <Window.Resources>

    <local:TaskListDataTemplateSelector x:Key="myDataTemplateSelector"/>

</Window.Resources>

Para utilizar el recurso selector de plantillas, asígnelo a la ItemTemplateSelector propiedad de la ListBox. El ListBox llamadas el SelectTemplate método de la TaskListDataTemplateSelector para cada uno de los elementos de la colección subyacente. La llamada pasa el objeto de datos como parámetro de elemento. El DataTemplate devuelto por el método, a continuación, se aplica a ese objeto de datos.

    <ListBox Width="400" Margin="10"
             ItemsSource="{Binding Source={StaticResource myTodoList}}"
             ItemTemplateSelector="{StaticResource myDataTemplateSelector}"
             HorizontalContentAlignment="Stretch"/>

Con el selector de plantilla en su lugar, el ListBox aparece ahora como sigue:

Captura de pantalla de ejemplo de datos plantillas

Esto concluye la explicación de este ejemplo. Para obtener un ejemplo completo, vea Introducción al ejemplo de creación de plantillas de datos.

Aunque la ItemsControl no es el único tipo de control que puede utilizar un DataTemplate , es un escenario muy común para enlazar un ItemsControl a una colección. En el lo que pertenece un DataTemplate sección explicamos que la definición de la DataTemplate sólo debe preocuparse por la presentación de datos. Para saber cuándo no es adecuado usar un DataTemplate es importante comprender las diferentes propiedades de estilo y la plantilla proporcionadas por el ItemsControl. El ejemplo siguiente está diseñado para ilustrar la función de cada una de estas propiedades. El ItemsControl en este ejemplo se enlaza al mismo Tasks colección del ejemplo anterior. Demostración propósitos, los estilos y plantillas en este ejemplo son todas las declaradas inline.

    <ItemsControl Margin="10"
                  ItemsSource="{Binding Source={StaticResource myTodoList}}">
      <!--The ItemsControl has no default visual appearance.
          Use the Template property to specify a ControlTemplate to define
          the appearance of an ItemsControl. The ItemsPresenter uses the specified
          ItemsPanelTemplate (see below) to layout the items. If an
          ItemsPanelTemplate is not specified, the default is used. (For ItemsControl,
          the default is an ItemsPanelTemplate that specifies a StackPanel.-->
      <ItemsControl.Template>
        <ControlTemplate TargetType="ItemsControl">
          <Border BorderBrush="Aqua" BorderThickness="1" CornerRadius="15">
            <ItemsPresenter/>
          </Border>
        </ControlTemplate>
      </ItemsControl.Template>
      <!--Use the ItemsPanel property to specify an ItemsPanelTemplate
          that defines the panel that is used to hold the generated items.
          In other words, use this property if you want to affect
          how the items are laid out.-->
      <ItemsControl.ItemsPanel>
        <ItemsPanelTemplate>
          <WrapPanel />
        </ItemsPanelTemplate>
      </ItemsControl.ItemsPanel>
      <!--Use the ItemTemplate to set a DataTemplate to define
          the visualization of the data objects. This DataTemplate
          specifies that each data object appears with the Proriity
          and TaskName on top of a silver ellipse.-->
      <ItemsControl.ItemTemplate>
        <DataTemplate>
          <DataTemplate.Resources>
            <Style TargetType="TextBlock">
              <Setter Property="FontSize" Value="18"/>
              <Setter Property="HorizontalAlignment" Value="Center"/>
            </Style>
          </DataTemplate.Resources>
          <Grid>
            <Ellipse Fill="Silver"/>
            <StackPanel>
              <TextBlock Margin="3,3,3,0"
                         Text="{Binding Path=Priority}"/>
              <TextBlock Margin="3,0,3,7"
                         Text="{Binding Path=TaskName}"/>
            </StackPanel>
          </Grid>
        </DataTemplate>
      </ItemsControl.ItemTemplate>
      <!--Use the ItemContainerStyle property to specify the appearance
          of the element that contains the data. This ItemContainerStyle
          gives each item container a margin and a width. There is also
          a trigger that sets a tooltip that shows the description of
          the data object when the mouse hovers over the item container.-->
      <ItemsControl.ItemContainerStyle>
        <Style>
          <Setter Property="Control.Width" Value="100"/>
          <Setter Property="Control.Margin" Value="5"/>
          <Style.Triggers>
            <Trigger Property="Control.IsMouseOver" Value="True">
              <Setter Property="Control.ToolTip"
                      Value="{Binding RelativeSource={x:Static RelativeSource.Self},
                              Path=Content.Description}"/>
            </Trigger>
          </Style.Triggers>
        </Style>
      </ItemsControl.ItemContainerStyle>
    </ItemsControl>

Ésta es una captura de pantalla del ejemplo cuando se representa:

Captura de pantalla de ejemplo ItemsControl

Tenga en cuenta que en lugar de utilizar el ItemTemplate, puede utilizar el ItemTemplateSelector. Consulte la sección anterior para obtener un ejemplo. De forma similar, en lugar de utilizar el ItemContainerStyle, tiene la opción de utilizar la ItemContainerStyleSelector.

Dos otras propiedades relacionadas con el estilo de la ItemsControl que no se muestran aquí son GroupStyle y GroupStyleSelector.

Hasta ahora sólo hemos examinado cómo enlazar y mostrar una sola colección. A veces tiene una colección que contiene otras colecciones. El HierarchicalDataTemplate clase está diseñada para usarse con HeaderedItemsControl tipos a mostrar dichos datos. En el ejemplo siguiente, ListLeagueList es una lista de League objetos. Cada League objeto tiene una Name y una colección de Division objetos. Cada Division tiene un Name y una colección de Team objetos y cada Team objeto tiene una Name.

<Window x:Class="SDKSample.Window1"
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  Title="HierarchicalDataTemplate Sample"
  xmlns:src="clr-namespace:SDKSample">
  <DockPanel>
    <DockPanel.Resources>
      <src:ListLeagueList x:Key="MyList"/>

      <HierarchicalDataTemplate DataType    = "{x:Type src:League}"
                                ItemsSource = "{Binding Path=Divisions}">
        <TextBlock Text="{Binding Path=Name}"/>
      </HierarchicalDataTemplate>

      <HierarchicalDataTemplate DataType    = "{x:Type src:Division}"
                                ItemsSource = "{Binding Path=Teams}">
        <TextBlock Text="{Binding Path=Name}"/>
      </HierarchicalDataTemplate>

      <DataTemplate DataType="{x:Type src:Team}">
        <TextBlock Text="{Binding Path=Name}"/>
      </DataTemplate>
    </DockPanel.Resources>

    <Menu Name="menu1" DockPanel.Dock="Top" Margin="10,10,10,10">
        <MenuItem Header="My Soccer Leagues"
                  ItemsSource="{Binding Source={StaticResource MyList}}" />
    </Menu>

    <TreeView>
      <TreeViewItem ItemsSource="{Binding Source={StaticResource MyList}}" Header="My Soccer Leagues" />
    </TreeView>

  </DockPanel>
</Window>

El ejemplo muestra que, con el uso de HierarchicalDataTemplate, puede mostrar fácilmente datos de la lista que contiene otras listas. La siguiente es una captura de pantalla del ejemplo.

Captura de pantalla de ejemplo HierarchicalDataTemplate

Enlace de datos
Buscar elementos generados por el DataTemplate
Estilos y plantillas
Información general sobre el enlace de datos
Información general sobre plantillas y estilos de encabezado de columna de GridView

Mostrar: