【问题标题】:How to defer data querying in Silverlight ViewModel class?如何推迟 Silverlight ViewModel 类中的数据查询?
【发布时间】:2011-05-21 18:08:31
【问题描述】:

我有一个 Silverlight 应用,上面有几个图表和一个日期控件,允许用户设置日期范围(例如 7 月 1 日 - 9 月 30 日)。

基本上,当用户修改日期范围时,会执行一个命令,将 ViewModel 的 DateRange 属性设置为新值。 DateRange 的设置器调用 RunQueries 方法,该方法查询新数据并使用这些查询的结果设置 Data1 和 Data2 属性。绑定到Data1 或Data2 的图表会相应更新。请参阅下面的基本 ViewModel 代码;记下DateRange setter 中的RunQueries 方法调用。

现在实际上,已经有两个以上的数据集合,并且随着应用程序的扩展,还会继续添加更多数据集合。此外,并非所有图表都同时可见;有时只有一张图表可见。但是,当用户更改日期范围时,获取任何图表所需的所有数据的所有查询都将使用新的开始日期和结束日期重新运行。这对我来说似乎非常低效 - 可能只需要运行一个查询!

所以我的问题是 - 如何在我的 ViewModel 类中实现延迟数据查询?

以下是我一直在考虑的两个想法:

  • 跟踪哪些数据集合是最新的,然后在需要运行查询时检查数据获取器方法。
  • 将 ViewModel 分解为几个子类,每个子类一个,并让每个 ViewModel 管理自己的数据,基类跟踪 DateRange。

这两个想法实施起来似乎很复杂,我一直在想 - 有没有标准的方法来解决这个问题?我是否遗漏了解决此问题的 MVVM 设计模式中的某些内容?


这是我的 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
}

【问题讨论】:

    标签: c# silverlight mvvm viewmodel


    【解决方案1】:

    我会试着总结一下你的情况:

    • 如果数据范围发生变化 - 只应更新可见图表。
    • 如果有任何图表可见 - 它应立即自行更新。

    因此显然需要可见性属性。

    第1点的解决方法:在RunQueries方法中检查命令执行的可能性。

    第二点的解决方案:在可见性属性的设置器中执行命令。

    示例如下:

    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
        }
    

    现在每个图表都有属性 Data、IsVisible、UpdateDataCommand 和方法 GetData。 我建议将它们移动到单独的视图模型中。

    【讨论】:

    • 出色的答案和出色的设计!我不会想到使用命令,但它实际上是一个不错的选择,并且在某些时候可以非常简单地实现“刷新数据”按钮。谢谢!
    • 在需要共享某些数据(例如 DateRange)的情况下,您如何建议使用多个 ViewModel 类?使用组合并让每个图的 ViewModel 包含对共享 ViewModel 的引用?还是使用某种继承?
    • 是的,需要将 DateRange 属性添加到其他视图模型。一种可能的方法是在两个视图模型中使用 DependencyProperties 并将一个属性绑定到另一个。但它需要继承 DependencyObject,有时可能会很不方便。所以我宁愿在属性 MyViewModel.DateRange 的设置器中使用 foreach 循环,如下所示:foreach(GraphViewModel vm in this.GraphModels) vm.UpdateDateRange(value);
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-10-08
    • 2016-08-18
    • 2022-10-14
    • 1970-01-01
    • 2012-11-11
    • 2011-05-24
    • 2023-03-04
    相关资源
    最近更新 更多