如何在Silverlight ViewModel类中推迟数据查询?

发布于 2024-10-06 04:30:53 字数 2209 浏览 0 评论 0原文

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

基本上,当用户修改日期范围时,会执行一条命令,将 ViewModel 的 DateRange 属性设置为新值。 DateRange 的 setter 调用 RunQueries 方法,该方法查询新数据并使用以下命令设置 Data1Data2 属性这些查询的结果。绑定到 Data1Data2 的图表会相应更新。请参阅下面的基本 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
}

I have a Silverlight app with several graphs and a date control on the top which allows the user to set the date range (e.g. July 1 - Sep 30).

Basically, when a user modifies the date range, a command is executed which sets the ViewModel's DateRange property to the new value. The DateRange's setter calls a RunQueries method which queries for new data and sets the Data1 and Data2 properties with the results of those queries. The graphs that are bound to Data1 or Data2 get updated accordingly. See below for the basic ViewModel code; take note of the RunQueries method call in the DateRange setter.

Now in reality, there are already more than two data collections and more keep on being added as the app is expanded. In addition, not all graphs are visible at once; at times only one graph is visible. But when the user changes the date range, all the queries to obtain all the data that is needed for any of the graphs are rerun with the new start and end dates. This seems very inefficient to me - perhaps only one query needs to be run!

So my question is - how do I implement delayed data querying in my ViewModel class?

Here are two ideas I've been considering:

  • Keep track of which data collections are up-to-date and then check in the data getter method if a query needs to be run.
  • Break out the ViewModel into several subclasses, one for each graph, and have each ViewModel manage its own data with the base class keeping track of the DateRange.

Both ideas seem complex to implement and I've been wondering - is there a standard approach to this? Am I missing something in the MVVM design pattern that addresses this issue?


Here's the very simplified version of my ViewModel class:

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
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

枕梦 2024-10-13 04:30:54

我将尝试总结您的情况:

  • 如果数据范围发生更改 - 仅应更新可见图表。
  • 如果任何图表变得可见 - 它应该立即更新自身。

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

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

第二点的解决方案:在 Visibility 属性的 setter 中执行命令。

下面是示例:

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。
我建议将它们移至单独的视图模型中。

I'll try to summarize your situation:

  • If data range is changed - only visible graphs should be updated.
  • If any graph becomes visible - it should update itself immediately.

So there is obvious need for a visibility property.

Solution for the 1st point: check possibility of command's execution in the RunQueries method.

Solution for the 2nd point: execute command in a setter of Visibility property.

Here is example:

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
    }

Each graph now has properties Data, IsVisible, UpdateDataCommand and method GetData.
I recommend to move them into a separate viewmodel.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文