Empezando con Windows Phone 7.1 (y XIV) – Asignando Comandos a Eventos.

En anteriores posts hemos visto que algunos controles de presentación, como la Barra de Aplicación, no son sencillos de montar con un patrón MVVM (fundamentalmente porque son objetos del shell y no objetos Silverlight).

En este caso vamos a ver como otros controles Silverlight que no se ajustan exactamente al modelo y, aun así, podremos manejar eventos con facilidad utilizando el patrón.

Para ello vamos a basarnos en una página de configuración que estoy montando en mi próximo proyecto.

 

image

Como podéis ver, los dos controles inferiores permiten activar y desactivar notificaciones (Live Tiles y Toast Notifications). Ambos controles son de la clase ToggleSwitch.

La clase ToggleSwitch describe eventos para manjar (entre otros) el Click, Checked y Unchecked. Sin embargo, no dispone de la posibilidad de invocar un comando (como sí pasa con Button).

Aquí es donde vamos a trabajar con una funcionalidad incorporada en el SDK 7.1 que nos permitirá asociar fácilmente (y de forma declarativa) eventos a comandos.

Lo primero es hacer referencia en la página al siguiente espacio de nombres.

   1:  

   2: xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"

   3:  

A continuación, en cada uno de los controles declararemos “disparadores” (Triggers) que invocarán un comando.

   1: <tool:ToggleSwitch Grid.Column="1" x:Name="PermitirTiles" Header="{Binding Source={StaticResource LocationHelper}, Path=Recursos.PermitirActiveTiles}" Content="{Binding Path=TextoActivarTiles}" IsChecked="{Binding Path=ActivarTiles}">

   2:    <i:Interaction.Triggers>

   3:        <i:EventTrigger EventName="Checked">

   4:            <i:InvokeCommandAction Command="{Binding Path=ComandoActivarTiles}" CommandParameter="{Binding ElementName=PermitirTiles, Path=IsChecked}" />

   5:        </i:EventTrigger>

   6:  

   7:        <i:EventTrigger EventName="Unchecked">

   8:            <i:InvokeCommandAction Command="{Binding Path=ComandoActivarTiles}" CommandParameter="{Binding ElementName=PermitirTiles, Path=IsChecked}" />

   9:        </i:EventTrigger>

  10:    </i:Interaction.Triggers>

  11: </tool:ToggleSwitch>

Como podéis ver, en este caso se disparan “Triggers” en los eventos Checked y Unchecked del control, en ambos casos se invoca al mismo comando y, en ambos casos pasando como parámetro la propiedad "IsChecked” del propio control. La diferencia es que, dependiendo del evento lanzado, dicha propiedad valdrá true o false.

A continuación en el ModeloVista declaremos las siguientes propiedades (he eliminado algo de código para facilitar el seguimiento).

   1: public class ConfiguracionViewModel : ViewModelBase

   2: {

   3:     private ICommand _comandoActivarTiles;

   4:     private ICommand _comandoActivarToast;

   5:  

   6:     /// <summary>

   7:     /// Initializes a new instance of the ConfiguracionViewModel class.

   8:     /// </summary>

   9:     /// <param name="dataService">Instancia de <see cref="IConfiguracionDataService"/> que proporciona acceso al servicio de datos</param>

  10:     public ConfiguracionViewModel(IConfiguracionDataService dataService)

  11:     {

  12:         if (dataService != null)

  13:             _dataService = dataService;

  14:     

  15:         // Creamos el comando para activar /desactivar tiles y el de activar /desactivar toast

  16:         _comandoActivarTiles = new RelayCommand<bool>((bool p) => ActivarTiles = p);

  17:         _comandoActivarToast = new RelayCommand<bool>((bool p) => ActivarToast = p);

  18:     

  19:         LoadData();

  20:     }

  21:  

  22:     private static readonly string TextoActivarTilesNombreProp = "TextoActivarTiles";

  23:  

  24:     /// <summary>

  25:     /// Texto que se mostrará dependiendo del estado actual de la activación de tiles

  26:     /// </summary>

  27:     public string TextoActivarTiles

  28:     {

  29:         get { return _textoActivarTiles; }

  30:         private set

  31:         {

  32:             _textoActivarTiles = value;

  33:             RaisePropertyChanged(TextoActivarTilesNombreProp);

  34:         }

  35:     }

  36:  

  37:     private static readonly string TextoActivarToastNombreProp = "TextoActivarToast";

  38:  

  39:     /// <summary>

  40:     /// Texto que se mostrará dependiendo del estado actual de la activación de tiles

  41:     /// </summary>

  42:     public string TextoActivarToast

  43:     {

  44:         get { return _textoActivarToast; }

  45:         private set

  46:         {

  47:             _textoActivarToast = value;

  48:             RaisePropertyChanged(TextoActivarToastNombreProp);

  49:         }

  50:     }

  51:  

  52:     /// <summary>

  53:     /// Propiedad que permite acceder al comando de activación /desactivación de tiles

  54:     /// </summary>

  55:     public ICommand ComandoActivarTiles

  56:     {

  57:         get { return _comandoActivarTiles; }

  58:     }

  59:  

  60:     /// <summary>

  61:     /// Propiedad que permite acceder al comando de activación /desactivación de notificaciones Toast

  62:     /// </summary>

  63:     public ICommand ComandoActivarToast

  64:     {

  65:         get { return _comandoActivarToast; }

  66:     }

  67:  

  68:     private static readonly string ActivarTilesNombreProp = "ActivarTiles";

  69:  

  70:     /// <summary>

  71:     /// Permite acceder al valor que indica si los tiles activos están o no habilitados

  72:     /// </summary>

  73:     public bool? ActivarTiles

  74:     {

  75:         get { return _preferencias.EnableTileNotif; }

  76:         set

  77:         {

  78:             if (_preferencias.EnableTileNotif == value)

  79:                 return;

  80:  

  81:             _preferencias.EnableTileNotif = value;

  82:             TextoActivarTiles = ObtenerCaptionToggleSwitch(value);

  83:  

  84:             RaisePropertyChanged(ActivarTilesNombreProp);

  85:         }

  86:     }

  87:  

  88:     private static readonly string ActivarToastNombreProp = "ActivarToast";

  89:  

  90:     /// <summary>

  91:     /// Permite acceder al valor que indica si las notificaciones toast están o no habilitadas

  92:     /// </summary>

  93:     public bool? ActivarToast

  94:     {

  95:         get { return _preferencias.EnableToastNotif; }

  96:         set

  97:         {

  98:             if (_preferencias.EnableToastNotif == value)

  99:                 return;

 100:  

 101:             _preferencias.EnableToastNotif = value;

 102:             TextoActivarToast = ObtenerCaptionToggleSwitch(value);

 103:  

 104:             RaisePropertyChanged(ActivarToastNombreProp);

 105:         }

 106:     }

 107:  

 108:     /// <summary>

 109:     /// Devuelve una cadena con el título de un ToggleSwitch en función del valor pasado como parámetro.

 110:     /// </summary>

 111:     /// <param name="param">Valor booleano asociado al estado del ToggleSwitch</param>

 112:     /// <returns>Cadena con el título que debe de mostrar el ToggleSwitch</returns>

 113:     private static string ObtenerCaptionToggleSwitch(bool? param)

 114:     {

 115:         return (param.HasValue && param.Value) ? Resources.CaptionActivo : Resources.CaptionInactivo;

 116:     }

 117: }

Esencialmente se crean comandos que cambian el valor del modelo y los literales asociados al estado del control (buscando dichos literales en los recursos).

La clase RelayCommand está declarada en el framework MVVM Light.

El código no está limpio pero probado y funciona.

image

Anuncios