2010-12-07 21 views
5

Tengo una aplicación Silverlight con varios gráficos y un control de fecha en la parte superior que permite al usuario establecer el intervalo de fechas (por ejemplo, del 1 de julio al 30 de septiembre).Cómo aplazar la consulta de datos en la clase Silverlight ViewModel?

Básicamente, cuando un usuario modifica el rango de fechas, se ejecuta un comando que establece la propiedad DateRange de ViewModel en el nuevo valor. El programador DateRange llama al método RunQueries que consulta los datos nuevos y establece las propiedades Data1 y Data2 con los resultados de esas consultas. Los gráficos que están limitados a Data1 o Data2 se actualizan en consecuencia. Vea a continuación el código básico de ViewModel; tome nota de la llamada al método RunQueries en el setter DateRange.

Ahora, en realidad, ya se han agregado más de dos colecciones de datos y más a medida que se amplía la aplicación. Además, no todos los gráficos son visibles a la vez; a veces, solo un gráfico es visible. Pero cuando el usuario cambia el intervalo de fechas, todas las consultas para obtener todos los datos que se necesitan para cualquiera de los gráficos se vuelven a ejecutar con las nuevas fechas de inicio y finalización. Esto me parece muy ineficiente, ¡quizás solo se necesite ejecutar una consulta!

Así que mi pregunta es: ¿cómo implemento la consulta de datos diferidos en mi clase ViewModel?

Éstos son dos ideas que he estado considerando: pista

  • Mantener las cuales las colecciones de datos están al día y después comprobar en el método de obtención de datos si una consulta necesita ser ejecutado.
  • Divida el ViewModel en varias subclases, una para cada gráfico, y haga que cada ViewModel administre sus propios datos con la clase base manteniendo un registro del DateRange.

Ambas ideas parecen complejas de implementar y me he estado preguntando: ¿existe un enfoque estándar para esto? ¿Me falta algo en el patrón de diseño de MVVM que resuelve este problema?


Aquí está la versión muy simplificada de mi clase ViewModel:

public class MyViewModel: INotifyPropertyChanged 
{ 
    private ObservableCollection<MyData> _Data1; 
    private ObservableCollection<MyData> _Data2; 
    private MyDateRange _DateRange; 

    public ObservableCollection<MyData> Data1 
    { 
     get 
     { 
      return _Data1; 
     } 
     set 
     { 
      if (_Data1 != value) 
      { 
       _Data1 = value; 
       NotifyPropertyChanged("Data1"); 
      } 
     } 
    } 

    // getter and setter for Data2 go here 

    public MyDateRange DateRange 
    { 
     get 
     { 
      return _DateRange; 
     } 
     set 
     { 
      if (_DateRange != value) 
      { 
       _DateRange = value; 
       NotifyPropertyChanged("DateRange"); 

       // if date range changed, need to query for stats again 
       RunQueries(); 
      } 
     } 
    } 

    private void RunQueries() 
    { 
      GetData1(); 
      GetData2(); 
    } 

    private void GetData1() 
    { 
      // call wcf service to get the data 
    } 

    private void GetData1Completed(object s, EventArgs e) 
    { 
      // update Data1 property with results of service call 
    } 

    // etc 
} 

Respuesta

1

voy a tratar de resumir su situación:

  • Si se cambia el rango de datos - sólo deben ser gráficos visibles actualizado.
  • Si algún gráfico se vuelve visible, debe actualizarse inmediatamente.

Por lo tanto, es evidente la necesidad de una propiedad de visibilidad.

Solución para el 1er punto: compruebe la posibilidad de ejecutar comandos en el método RunQueries.

Solución para el segundo punto: ejecutar el comando en un setter de la propiedad Visibilidad.

Aquí es ejemplo:

private DelegateCommand UpdateData1Command { get; set; } 

    public MyViewModel() 
    { 
     this.UpdateData1Command = new DelegateCommand(_ => this.GetData1(), _ => this.IsGraph1Visible); 
    } 

    private bool isGraph1Visible; 

    public bool IsGraph1Visible 
    { 
     get { return isGraph1Visible; } 
     set 
     { 
      isGraph1Visible = value; 
      OnPropertyChanged("IsGraph1Visible"); 

      if(UpdateData1Command.CanExecute(null)) 
       UpdateData1Command.Execute(null); 
     } 
    } 

    private void RunQueries() 
    { 
     if (UpdateData1Command.CanExecute(null)) 
      UpdateData1Command.Execute(null); 
    } 

    private void GetData1() 
    { 
     // call wcf service to get the data 
    } 

Cada gráfico tiene ahora propiedades de datos, IsVisible, UpdateDataCommand y el método GetData. Recomiendo moverlos a un modelo de vista separado.

+0

¡Excelente respuesta y un gran diseño! No hubiera pensado en usar comandos, pero en realidad es una buena opción y hará que sea muy sencillo implementar un botón de "actualizar datos" en algún momento. ¡Gracias! – MCS

+0

¿Cómo sugeriría usar múltiples clases de ViewModel en un caso como este en el que se deben compartir algunos de los datos (por ejemplo, DateRange)? Use la composición y haga que el ViewModel de cada gráfico contenga una referencia al ViewModel compartido. O usar algún tipo de herencia? – MCS

+0

Sí, es necesario agregar una propiedad DateRange al otro modelo de vista. Una de las formas posibles es usar DependencyProperties en ambos viewmodels y vincular una propiedad a otra. Pero requiere una herencia de DependencyObject y puede ser inconveniente a veces. Por lo tanto, prefiero usar foreach loop dentro del setter de la propiedad MyViewModel.DateRange, algo como esto: foreach (GraphViewModel vm en this.GraphModels) vm.UpdateDateRange (value); – vorrtex

Cuestiones relacionadas