Comandos, Parámetros y MVVM


Los comandos son un buen agregado al patrón MVVM pues esto permite manejar los eventos desde el ViewModel (VM). En el anterior artículo vimos el comando Ingresar, el cual nos permitía “iniciar sesión” cuando los valores que se ingresaban eran correctos. Esta vez quiero explicar un poco más acerca de los Comandos y me voy a valer de un ejemplo; además mostrar que los parámetros que se asignan al comando pueden ser triviales, como texto de un TextBox, usar un convertidor para crear un Model como lo vimos en al artículo pasado o,como vamos a ver hoy, para pasar un Control.

Crearemos un programa el cual va a añadir o eliminar Elipses (Ellipse), las cuáles crearemos en nuestro VM como puntos -de tipo Points-. estas elipses serán dibujadas en un ItemsControl al cual llamaremos Contenedor y el cuál almacenará un control contenedor (en este caso usaremos Canvas) y ahí se dibujarán los puntos usando los valores de X y Y que nos suministre el punto del VM. Utilizaremos 2 Botones los cuales nos ayudarán a Agregar o Eliminar puntos.

Comencemos con el VM de nuestro ejemplo pues en este proyecto no usaremos un modelo.

Usaremos un ObservableCollection de Points, ya hemos usado este tipo de colección así que si necesita más información puede consultar la MSDN Library

public Punto ()
{
    PointList = new ObservableCollection<Point> ();
}

public ObservableCollection<Point> PointList { get; set; }

Para nuestro comando Agregar haremos lo siguiente usando el RelayCommand de Josh Smith:

public ICommand Agregar
{
    get
    {
        return AgregarCommand = new RelayCommand ( addPoint, param => canAdd () );
    }
}

private void addPoint (object parameter)
{
    ItemsControl contenedor = parameter as ItemsControl;
    if ( contenedor != null )
    {
        Random rnd = new Random ();
        double x = rnd.Next ( 0, ( ( int )contenedor.ActualWidth ) );
        double y = rnd.Next ( 0, ( ( int )contenedor.ActualHeight ) );
        PointList.Add ( new Point ( x, y ) );
    }
}

private bool canAdd ()
{
    return PointList.Count &lt; 100;
}

Nuestro comando Agregar se activa mientras la lista de puntos sea menor a 100 (como vemos en la función canAdd), con respecto a addPoint podemos ver que tratamos de convertir nuestro parámetro como un ItemsControl, si lo logra convertir creamos 2 valores double para nuestro punto usando Random entre 0 y el tamaño actual (ya sea Ancho o Alto) y luego añadimos nuestro punto a PointList.

Ahora miremos el comando de Eliminar:

public RelayCommand EliminarCommand
{
    get;
    private set;
}

public ICommand Eliminar
{
    get
    {
        return EliminarCommand = new RelayCommand ( removePoint, param => canRemove () );
    }
}

private void removePoint (object parameter)
{
    Random rnd = new Random ();
    int x = rnd.Next ( 0, PointList.Count );
    PointList.RemoveAt ( x );
}

private bool canRemove ()
{
    return PointList.Count &gt; 0;
}

Al igual que nuestro comando Agregar, nuestro comando Eliminar es bastante sencillo; se activa mientras PointList tenga puntos y removePoint borra un punto aleatoriamente usando Random entre 0 y la lista completa.

Ahora vamos a hacer unas pequeñas explicaciones. en mi caso trabajo con RelayCommand de Josh Smith, pues de esta manera se puede aplicar el patrón MVVM de forma completa; a diferencia de este existen los RoutedCommand y RoutedEvents que hacen uso del code-behind que es lo que no se quiere al usar el patrón MVVM.
Nota: si se pude usar RoutedCommand con el patrón MVVM, aunque es un poco mas complicado, aquí dejo la referencia Using RoutedCommand with a ViewModel in WPF.

Por ultimo veamos nuestra ventana. EL xaml quedaría de esta forma:

<Window x:Class="Puntos.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:c="clr-namespace:Puntos"
        Title="Puntos" Height="350" Width="525">
    <Window.Resources>
        <c:Punto x:Key="PuntoData"/>
    </Window.Resources>
    <Grid DataContext="{Binding Source={StaticResource PuntoData}}">
        <ItemsControl Name="Contenedor" ItemsSource="{Binding PointList}"
                  Width="450" Height="250" VerticalAlignment="Top">
			<ItemsControl.ItemsPanel>
				<ItemsPanelTemplate>
					<Canvas />
				</ItemsPanelTemplate>
			</ItemsControl.ItemsPanel>
			<ItemsControl.ItemTemplate>
				<DataTemplate>
					<Ellipse Fill="Black" Width="25" Height="25" />
				</DataTemplate>
			</ItemsControl.ItemTemplate>
			<ItemsControl.ItemContainerStyle>
				<Style>
				    <Setter Property="Canvas.Left" Value="{Binding Path=X}" />
				    <Setter Property="Canvas.Top" Value="{Binding Path=Y}" />
				</Style>
			</ItemsControl.ItemContainerStyle>
		</ItemsControl>
        <Button x:Name="Agregar" Height="30" Width="100" Content="Agregar"
                VerticalAlignment="Bottom" Margin="120,0,0,10"
                HorizontalAlignment="Left" Command="{Binding Agregar}"
                CommandParameter="{Binding ElementName=Contenedor}"/>

        <Button x:Name="Eliminar" Height="30" Width="100" Content="Eliminar"
                VerticalAlignment="Bottom" Margin="0,0,120,10"
                HorizontalAlignment="Right" Command="{Binding Eliminar}"/>
    </Grid>
</Window>

Como ya les había dicho, creamos un ItemsControl cuyo contenedor (ItemsPanel) es un Canvas El cual pintará Elipses de 25 x 25 de color Negro, las cuáles se dibujarán usando las coordenadas X y Y tomando como referencia la esquina superior izquierda como base.

Esto es todo por ahora, espero que les guste este pequeño ejemplo y que prueben usando otro tipo de figuras. Les dejo el link de descarga y una imagen de cómo se ve el programa. Puntos.zip, les recuerdo cambiar la extensión de odt a zip.

Anuncios

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s