Datos de ejemplo en el ViewModel para facilitar la vista de diseño

Al trabajar con XAML, especialmente si la vista tiene un listado de items, puede resultar muy complicado ajustar la vista para que se vea correctamente. Tareas como ajustar los márgenes, la posición de los elementos o cualquier tipo de cambio en los estilos se pueden convertir en algo bastante pesado.

Este es un ejemplo de una vista de que contiene un ListView sin datos de ejemplo en vista de diseño:

ventana con listview vacío

La imagen corresponde a la vista de diseño de un código como este:

<ListBox ItemsSource="{Binding SampleData}">
    <ListBox.ItemTemplate>
        <DataTemplate>
            <TextBlock Text="{Binding Name}"></TextBlock>
        </DataTemplate>
    </ListBox.ItemTemplate>
</ListBox>

Este es un ejemplo que ilustra bastante bien el problema, no se ve nada. Se trata de un fragmento de XAML muy sencillo y no presenta grandes problemas para intuir lo que se va a pintar, pero en cuanto la cosa se complica un poco más, ir a ciegas no resulta nada agradable. Como no tenemos datos de ejemplo, no somos capaces de saber cómo van a mostrarse los items de la lista y cualquier tipo de cambio se hace a ciegas. Para cambios pequeños, se recurre al ensayo y error, pero esto es una solución muy engorrosa y poco fluida. Para evitar ir a ciegas tenemos que hacer dos cosas:

Paso 1

Decirle a la vista que cree una instancia del ViewModel en vista de diseño:

xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:wpfApplication1="clr-namespace:WpfApplication1"
mc:Ignorable="d"
d:DataContext="{d:DesignInstance Type=wpfApplication1:SampleViewModel, IsDesignTimeCreatable=True}"

La clave está en la última línea. El tipo del ViewModel es SampleViewmodel y al poner a true el IsDesignTimeCreatablele, se hablilita la creación de una instancia del viewmodel en vista de diseño.

Paso 2

Para hacer que el ViewModel tenga datos de ejemplo, lo único necesario es asignar los datos en el constructor. En la vista de ejemplo se puede llamar desde el constructor a un método que haga algo como esto:

if (DesignerProperties.GetIsInDesignMode(new DependencyObject()))
{
    var sampleData = new List<ClientData>();
    sampleData.Add(new ClientData() { Name = "Sample Client 1", Email = "email@domain.com" });
    sampleData.Add(new ClientData() { Name = "Sample Client 2", Email = "email@domain.com" });
    sampleData.Add(new ClientData() { Name = "Sample Client 3", Email = "email@domain.com" });
    sampleData.Add(new ClientData() { Name = "Sample Client 4", Email = "email@domain.com" });
    sampleData.Add(new ClientData() { Name = "Sample Client 5", Email = "email@domain.com" });
    sampleData.Add(new ClientData() { Name = "Sample Client 6", Email = "email@domain.com" });

    SampleData = new ObservableCollection<ClientData>(sampleData);
}

Es muy importante que únicamente se rellenen los datos en vista de diseño, para que no se rellenen durante la ejecución de la aplicación. Por eso el if de la primera línea.

Una vez hecho esto, todos los bindings de datos con el ViewModel mostrarán los datos de ejemplo en vista de diseño, pudiendo así hacer los ajustes de estilos sin necesidad de ejecutar la aplicación. Por ejemplo:

<Window x:Class="WpfApplication1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:wpfApplication1="clr-namespace:WpfApplication1"
        mc:Ignorable="d"
        d:DataContext="{d:DesignInstance Type=wpfApplication1:SampleViewModel, IsDesignTimeCreatable=True}"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <ListBox ItemsSource="{Binding SampleData}">
            <ListBox.ItemTemplate>
                <DataTemplate>
                    <StackPanel Orientation="Horizontal">
                        <TextBlock Text="{Binding Name}"></TextBlock>
                        <TextBlock Text="{Binding Email}" Margin="15,0,0,0"></TextBlock>
                    </StackPanel>
                </DataTemplate>
            </ListBox.ItemTemplate>
        </ListBox>
    </Grid>
</Window>

Y así es como se vería en vista de diseño:

ventana con listview con datos de ejemplo

Si no quieres meter los datos de ejemplo en tu clase de ViewModel, siempre puedes crear una clase específica para el ViewModel en tiempo de diseño. Sólo hay que cambiar el valor del DesignInstance en el archivo XAML y darle el nombre del tipo para la vista de diseño. Eso si, mejor que recurras a interfaces o algo similar para asegurarte de que ambos ViewModel (el de vista de diseño y el que se ejecutará en real) compartan el mismo contrato.

 

**IMPORTANTE:** Para que las vistas tomen los datos de ejemplo debemos compilar el proyecto para que se compile el ViewModel. Si hacemos cambios en el conjunto de datos de ejemplos del ViewModel, deberemos compilar de nuevo, así que lo mejor es crear primero un conjunto de datos de ejemplo dignos y así luego podemos centrarnos en el trabajo de la vista.

Modesto San Juan

Desarrollo software e intento hacerlo bien