Cómo utilizar controles de lista para mostrar colecciones de datos en WinRT | C# | XAML

Intermedio

Las listas son de los controles más poderosos para mostrar datos que posee WinRT.

Para mostrar datos por ejemplo en un GridVew, basta con hacer esto:

 
<GridView>
    <Border Background="Goldenrod">
        <TextBlock Text="Texto"/>
    </Border>
    <Border Background="GreenYellow">
        <TextBlock Text="Texto"/>
    </Border>
    <Border Background="MidnightBlue">
        <TextBlock Text="Texto"/>
    </Border>
    <Border Background="Violet">
        <TextBlock Text="Texto"/>
    </Border>
    <Ellipse Width="50" Height="50" Fill="Red"/>
</GridView>

y el resultado será:

screenshot xaml

De este ejercicio podemos destacar lo siguiente:

Un GridView, y en general los controles de lista, pueden contener una lista de elementos sin importar que sean de tipos distintos.

Un contenedor de lista puede contener un número limitado de objetos establecidos estáticamente en tiempo de diseño, sin embargo en muchas ocasiones necesitamos que los contenidos de un control de lista sean establecidos dinámicamente o que incluso puedan cambiar durante el ciclo de vida de la aplicación, lo que debemos tener presente en este escenario es lo siguiente:

  • Debemos hacer Binding con una colección, establecerla como origen de datos para los items
  • Por cada miembro de la colección debemos hacer Binding con cada una de sus propiedades

Para poder revisar estos temas lo primero que necesitamos es definir un origen de datos, utilizaremos una List de Persona como datos de prueba. Necesitas datos de prueba?

Cómo generar datos aleatorios para realizar pruebas

Definimos nuestro origen de datos, guardaremos objetos de tipo Persona y para ellos heredamos de BindableBase el cual nos implementa ya INotifyPorpertyChanged.

 
public class Persona : BindableBase
{
    private int _cedula;
    public int Cedula
    {
        get { return _cedula; }
        set
        {
            _cedula = value;
            SetProperty(ref _cedula, value);
        }
    }

    private string _nombre;
    public string Nombre
    {
        get { return _nombre; }
        set
        {
            _nombre = value;
            SetProperty(ref _nombre, value);
        }
    }

    private string _apellido;
    public string Apellido
    {
        get { return _apellido; }
        set { SetProperty(ref _apellido, value); }
    }

    private string _profesion;
    public string Profesion
    {
        get { return _profesion; }
        set { SetProperty(ref _profesion, value); }
    }
}

Y creamos una clase capaz de inicializar una colección de datos de ese objeto.

 
public class DataSourcePersonas
{
    public ObservableCollection ListaPersonas { get; set; }

    public DataSourcePersonas()
    {
        Initialize();
    }

    public void Initialize()
    {
        var listaFull = Traer‌InfoDesdeOrigenDeDatos();
        ListaPersonas = new ObservableCollection(listaFull);
    }
}

Para hacer Binding con nuestra fuente de datos hay que asignar el atributo ItemsSource (No DataContext como se hace habitualmente) esto lo podemos hacer desde el code behind o desde el XAML, siendo esta última la recomendación para mantener un código mas desacoplado y mejor estructurado.

 
<Page
    x:Class="DemoGrouping.SimpleLists"
    xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:DemoGrouping"
    xmlns:data="using:DemoGrouping.Data"
    >
    <Page.Resources>
        <data:DataSourcePersonas x:Key="DatosPersonas"/>
    </Page.Resources>
    <Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}">
    </Grid>
</Page>

Ahora creamos el GridView y le asignamos la fuente de datos

 
<GridView ItemsSource="{Binding Source={StaticResource DatosPersonas},Path=ListaPersonas}">

</GridView>

Si la vida fuera muy fácil todos seriamos ricos y este demo ya estaría funcionando a la perfección! pero la vida no es fácil verdad?

Este es el resultado de lo que acabamos de hacer:

GridView Object names

Qué sucedio?

Persona es un objeto complejo, y cuando le hacemos binding WinRT aplica la transformación por defecto para el tipo object, esto es ToString() y el ToString de un object es el nombre del tipo de dato.

Cómo evitarlo?

De manera intuitiva, una forma de evitarlo es colocar los items estáticamente como lo hicimos arriba con los TextBlock así:

 
<GridView ItemsSource="{Binding Source={StaticResource DatosPersonas}, Path=ListaPersonas}">
    <Border>
        <StackPanel>
            <TextBlock Text="{Binding Nombre}"/>
            <TextBlock Text="{Binding Cedula}"/>
            <TextBlock Text="{Binding Profesion}"/>
        </StackPanel>
    </Border>
</GridView>

Pero el resultado sera el mismo… les dije que la vida no es fácil.

Pese a la intuición y al intento fallido no estamos muy lejos, lo que falta por hacer es decirle EXPLICITAMENTE a WinRT que deseamos que esos objetos hagan Binding con cada uno de los objetos asignados en ItemsSource, para ello modificamos el template del control, y es allí donde debemos dejar los controles creados anteriormente.

 
<GridView ItemsSource="{Binding Source={StaticResource DatosPersonas}, Path=ListaPersonas}">
    <GridView.ItemTemplate>
        <DataTemplate>
            <Border>
                <StackPanel>
                    <TextBlock Text="{Binding Nombre}"/>
                    <TextBlock Text="{Binding Apellido}"/>
                    <TextBlock Text="{Binding Cedula}"/>
                    <TextBlock Text="{Binding Profesion}"/>
                </StackPanel>
            </Border>
        </DataTemplate>
    </GridView.ItemTemplate>
</GridView>

GridView Template

Para obtener la visualización que muestro en la foto, debes aplicar estos estilos

 
<Style x:Key="border-st" TargetType="Border">
    <Setter Property="Background" Value="DarkKhaki"/>
    <Setter Property="Padding" Value="5"/>
    <Setter Property="Margin" Value="5"/>
    <Setter Property="Width" Value="230"/>
    <Setter Property="Width" Value="230"/>
</Style>
<Style x:Key="texblock-st" TargetType="TextBlock">
    <Setter Property="FontSize"  Value="40"/>
    <Setter Property="Foreground" Value="White"/>
    <Setter Property="TextWrapping" Value="Wrap"/>
</Style>

Quedando el código finalmente así:

 
<Page
    x:Class="DemoGrouping.SimpleLists"
    xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="https://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="https://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d"
    xmlns:local="using:DemoGrouping"
    xmlns:data="using:DemoGrouping.Data">
    <Page.Resources>
        <data:DataSourcePersonas x:Key="DatosPersonas"/>
        <Style x:Key="border-st" TargetType="Border">
            <Setter Property="Background" Value="DarkKhaki"/>
            <Setter Property="Padding" Value="5"/>
            <Setter Property="Margin" Value="5"/>
            <Setter Property="Width" Value="230"/>
            <Setter Property="Width" Value="230"/>
        </Style>
        <Style x:Key="texblock-st" TargetType="TextBlock">
            <Setter Property="FontSize"  Value="40"/>
            <Setter Property="Foreground" Value="White"/>
            <Setter Property="TextWrapping" Value="Wrap"/>
        </Style>
    </Page.Resources>
    <Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}" >
        <GridView ItemsSource="{Binding Source={StaticResource DatosPersonas}, Path=ListaPersonas}">
            <GridView.ItemTemplate>
                <DataTemplate>
                    <Border Style="{StaticResource border-st}">
                        <StackPanel>
                            <TextBlock Style="{StaticResource texblock-st}" Text="{Binding Nombre}"/>
                            <TextBlock Style="{StaticResource texblock-st}" Text="{Binding Apellido}"/>
                            <TextBlock Style="{StaticResource texblock-st}" Text="{Binding Cedula}"/>
                            <TextBlock Style="{StaticResource texblock-st}" Text="{Binding Profesion}"/>
                        </StackPanel>
                    </Border>
                </DataTemplate>
            </GridView.ItemTemplate>
        </GridView>
    </Grid>
</Page>

Espero les sea de ayuda.

Hasta pronto.