WPF& MVVM:耗时搜索结果的最佳架构?

时间:2010-08-11 18:21:09

标签: wpf architecture mvvm domain-driven-design

我正在为进行搜索的模块设计架构。 搜索需要一些时间,我希望UI能够响应,因此我将数据检索委托给将在单独的线程上进行搜索的类。

然后,我可以想到两个选择:

任一 1°:搜索方法返回一个视图模型,其中空数据作为返回值(占位符),但一旦搜索过程结束,视图模型的成员将被更新,并且结果显示在屏幕上,这要归功于数据绑定,

2°:搜索方法没有任何返回类型,但是一旦搜索过程结束,就会引发一个事件,并在事件args中传递带有最终值的viewmodel,这样它就可以被调用码。 (并最终被视图消耗)

对此有什么想法吗?

编辑:当然,使用解决方案1°我在搜索结果“占位符”对象返回的对象上引用WPF数据绑定

4 个答案:

答案 0 :(得分:2)

如果您使用BackgroundWorker,则会为您完成设计模式。在DoWork事件处理程序中调用您的搜索方法,并将结果放在传入的Results的{​​{1}}属性中。

使用DoWorkEventArgs事件处理程序中的结果更新UI(它们将位于RunWorkerCompleted对象的RunWorkerCompletedEventArgs属性中)。

如果要在搜索过程中更新UI,请让搜索方法调用Results并更新ReportProgress事件处理程序中的UI。您可以将任何您喜欢的内容放入ProgressChanged的{​​{1}}属性中,包括中间搜索结果,但您必须小心不要传递后台线程将要触摸的任何对象,因为它继续执行。

答案 1 :(得分:0)

我将利用数据绑定并将搜索结果表示控件绑定到可观察的搜索结果集合,并从后台工作线程更新ViewModel中的该集合。然后它不需要你的代码中的任何回调或更新消息,它只是你希望利用WPF中的管道工作。

答案 2 :(得分:0)

您还可以利用优先级绑定(http://msdn.microsoft.com/en-us/library/system.windows.data.prioritybinding.aspx)。它提供快/慢选项,您不必担心更新线程。当然,除非你想添加一些视觉效果,让用户知道正在发生的事情。

答案 3 :(得分:0)

这是我在最近的一个项目中所做的。

IsBusy属性是我在所有viewmodel的基类中所拥有的。如果一个视图想要显示某种等待控件(如微调器或其他类似的东西),它就是一个布尔值。

_retrieveData字段只是我在构建viewmodel期间设置的Action。我这样做是因为viewmodel可能以几种不同的方式得到它的Cars列表 - 所以_retrieveData可能会根据所使用的构造函数在其中包含不同的代码。在_retrieveData获取数据后,它将设置私有支持者_cars与数据。所以在完成_retrieveData之后,将公共Cars设置为_cars中新数据的值会导致PropertyChangedEvent让视图知道自己更新。

因此效果是当视图第一次获取数据时,它会立即返回但是为null。然后几秒钟后,它获得实际数据。在此期间,UI响应迅速。而且,如果用户界面想让用户知道它在后台工作,那么IsBusy就是如此。

不确定这是否是处理它的好方法,但到目前为止它对我有用。

public List<Car> Cars
{
   get
   {
       if (this._cars == null)
       {
           base.IsBusy = true;

           // Start a background thread to get the data...
           ThreadPool.QueueUserWorkItem(new WaitCallback(delegate(object nullObject)
           {
               this._retrieveData.Invoke();
               this.Cars = this._cars;
               base.IsBusy = false;
           }));

           // While waiting on the background thread, return null for now.  When the background thread
           // completes, the setter will raise OnPropertyChanged and the view will know its time to bind...
           return this._cars;
       }

       return this._cars;
   }
   set
   {
       this._cars = value;
       base.OnPropertyChanged("Cars");
   }

}