Cambiando la apariencia de un DataGrid automáticamente en un lapso de tiempo

Nuestro buen amigo Rodrigo Diaz escrbibio un excelente articulo, aqui el detalle:

Cambiando la apariencia de un DataGrid automáticamente en un lapso de tiempo

El día de hoy hicieron una pregunta muy interesante en el grupo de La Liga Silverlight en Facebook. Aquí la pongo textual:

“AYUDA!!!
Tengo un DataGrid en Silverlight con los siguientes campos {idhorario, horainicio, horafin, dia, idseccion}.
necesito que los campos {horainicio y horafin}, cambien de color en una Hora indicada, me explico, tengo una materia de 12:00 a 2:00pm, y son las 1:00pm en mi reloj, que estos campos aparezcan en otro COLOR… o que llamen la atencion de alguna manera.
COMO HAGO ESTO???”

Se me ocurren unas 3 o 4 maneras para resolver esto, pero decidí irme por la que creo yo la más eficiente: usar la característica de enlace en los setters de los estilos, disponible a partir de Silverlight 5.

¡Manos a la obra!

El Proyecto

Iniciaremos creando un proyecto regular de Silverlight 5 llamado Horarios usando la plantilla de Silverlight Application.

Clase Materia

La primera tarea será modelar la clase para cada materia. A esta clase la llamaremos Materia. A continuación podrán observar la implementación completa:

  1: 1: public class Materia : INotifyPropertyChanged 
  2:  
  3:    2: { 
  4:  
  5:    3:   
  6:  
  7:    4:     public SolidColorBrush ColorMateria 
  8:  
  9:    5:     { 
  10:  
  11:    6:         get 
  12:  
  13:    7:         { 
  14:  
  15:    8:             SolidColorBrush colorMateria = new SolidColorBrush(Colors.Black); 
  16:  
  17:    9:   
  18:  
  19:   10:             DateTime inicio = Helper.GetDateTimeFromHourMinuteString(HoraInicio); 
  20:  
  21:   11:             DateTime fin = Helper.GetDateTimeFromHourMinuteString(HoraFin); 
  22:  
  23:   12:   
  24:  
  25:   13:             if (DateTime.Now >= inicio && DateTime.Now <= fin) 
  26:  
  27:   14:             { 
  28:  
  29:   15:                 colorMateria = new SolidColorBrush(Colors.Red); 
  30:  
  31:   16:             } 
  32:  
  33:   17:   
  34:  
  35:   18:             return colorMateria; 
  36:  
  37:   19:         } 
  38:  
  39:   20:     } 
  40:  
  41:   21:   
  42:  
  43:   22:   
  44:  
  45:   23:     DispatcherTimer timer; 
  46:  
  47:   24:     public Materia() 
  48:  
  49:   25:     { 
  50:  
  51:   26:         if (timer == null) 
  52:  
  53:   27:         { 
  54:  
  55:   28:             timer = new DispatcherTimer() { Interval = TimeSpan.FromSeconds(1) }; 
  56:  
  57:   29:             timer.Tick += (s, a) => 
  58:  
  59:   30:             { 
  60:  
  61:   31:                 OnPropertyChanged("ColorMateria"); 
  62:  
  63:   32:             }; 
  64:  
  65:   33:   
  66:  
  67:   34:             timer.Start(); 
  68:  
  69:   35:         } 
  70:  
  71:   36:     } 
  72:  
  73:   37:         
  74:  
  75:   38:   
  76:  
  77:   39:     string nombre; 
  78:  
  79:   40:   
  80:  
  81:   41:     public string Nombre 
  82:  
  83:   42:     { 
  84:  
  85:   43:         get { return nombre; } 
  86:  
  87:   44:         set { nombre = value; 
  88:  
  89:   45:         OnPropertyChanged("Nombre"); 
  90:  
  91:   46:         } 
  92:  
  93:   47:     } 
  94:  
  95:   48:     string horaInicio; 
  96:  
  97:   49:   
  98:  
  99:   50:     public string HoraInicio 
  100:  
  101:   51:     { 
  102:  
  103:   52:         get { return horaInicio; } 
  104:  
  105:   53:         set { horaInicio = value; 
  106:  
  107:   54:         OnPropertyChanged("HoraInicio"); 
  108:  
  109:   55:         } 
  110:  
  111:   56:     } 
  112:  
  113:   57:     string horaFin; 
  114:  
  115:   58:   
  116:  
  117:   59:     public string HoraFin 
  118:  
  119:   60:     { 
  120:  
  121:   61:         get { return horaFin; } 
  122:  
  123:   62:         set { horaFin = value; 
  124:  
  125:   63:         OnPropertyChanged("HoraFin"); 
  126:  
  127:   64:         } 
  128:  
  129:   65:     } 
  130:  
  131:   66:   
  132:  
  133:   67:     void OnPropertyChanged(string propertyName) 
  134:  
  135:   68:     { 
  136:  
  137:   69:         if (PropertyChanged != null) 
  138:  
  139:   70:         { 
  140:  
  141:   71:             PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); 
  142:  
  143:   72:         } 
  144:  
  145:   73:     } 
  146:  
  147:   74:   
  148:  
  149:   75:     public event PropertyChangedEventHandler PropertyChanged; 
  150:  
  151:   76: }

Como podrán apreciar, esta clase implementa la intefaz INotifyPropertyChanged ya que estoy interesado en notificar a los bindings enlazados a sus propiedades que algún valor de dichas propiedades ha cambiado.

En el constructor, estoy inicializando un objeto de tipo DispatcherTimer, con un intervalo de 1 segundo. En el manejador del evento Tick de este objeto notifico a la infraestructura de bindings de Silverlight que la propiedad ColorMateria ha cambiado.

Propiedad ColorMateria

Esta propiedad es de tipo SolidColorBrush, pero pudiera ser de cualquier tipo concreto de la familia de clases Brush. El objetivo de esta propiedad será obtener los valores de las propiedades HoraInicio y HoraFin (ambas de tipo string), las cuales indican la hora de inicio y hora de finalización de dicha materia respectivamente. En la implementación estoy esperando un formato HH:MM ya que considero que el tipo DateTime no expresaría adecuadamente este valor (pero se los dejo a su consideración). Ahora bien, podrás darte cuenta que se invoca un método llamado GetDateTimeFromHourMinuteString(). Este método estático está implementado en una clase llamada Helper para no mezclar esta implementación dentro de la clase de nuestro modelo (Materia). El algoritmo para determinar el cambio de color es bastante sencillo: simplemente se evalúa si la hora actual está dentro de ese lapso.

GetDateTimeFromHourMinuteString()

Este método es súmamente sencillo, ya que su único objetivo es regresarnos un DateTime a partir de la cadena HH:MM que le pasemos en su único parámetro. Este DateTime es necesario para evaluar si la hora actual está dentro del lapso de duración de la materia, y de esa manera se dispare el cambio de color adecuadamente. A continuación podrás ver la implementación completa de la clase Helper.

  1: 1: public class Helper 
  2:  
  3: 2: { 
  4:  
  5: 3:     public static DateTime GetDateTimeFromHourMinuteString(string cadena) 
  6:  
  7: 4:     { 
  8:  
  9: 5:         try 
  10:  
  11: 6:         { 
  12:  
  13: 7:             var valores = cadena.Split(':'); 
  14:  
  15: 8:             int hora = int.Parse(valores[0]); 
  16:  
  17: 9:             int minuto = int.Parse(valores[1]); 
  18:  
  19: 0:   
  20:  
  21: 1:             return new DateTime(DateTime.Now.Year, 
  22:  
  23: 2:                                 DateTime.Now.Month, 
  24:  
  25: 3:                                 DateTime.Now.Day, 
  26:  
  27: 4:                                 hora, 
  28:  
  29: 5:                                 minuto, 
  30:  
  31: 6:                                 0); 
  32:  
  33: 7:         } 
  34:  
  35: 8:         catch 
  36:  
  37: 9:         { 
  38:  
  39: 0:             return DateTime.Now; 
  40:  
  41: 1:         } 
  42:  
  43: 2:             
  44:  
  45: 3:     } 
  46:  
  47: 4:   
  48:  
  49: 5: }

Datos

Claro está, necesitamos una lista de datos. La clase Datos fungirá como nuestro ViewModel de la aplicación, y expondrá una sola propiedad llamada ListaMaterias de tipo ObservableCollection<Materia>. En este caso y a falta de una fuente de datos real he implementado datos “dummy” en el get{} de la propiedad. No obstante, para efectos de prueba es una excelente opción para corroborar la funcionalidad que estamos buscando. ListaMaterias decidí implementarla de tipo ObservableCollection para que sus datos posteriormente puedan ser cargados dinámicamente y que automáticamente el control o los controles enlazados sean notificados del cambio de la colección.

Ver el articulo completo aqui.

saludos

Fernando García Loera (Community Program Manager – Latin America Region)

Icono Ferglo 40x116twitter 40x40RSS 40x40facebook 40x116linkedin40x40xbox 40x40

Que es un MVP? Tips para ser MVP