2010-08-11 65 views
2

我正在为搜索发生的模块设计架构。 搜索需要一些时间,并且我希望UI具有响应性,所以我可以将数据的检索委托给将在单独的线程上执行搜索的类。WPF和MVVM:耗时搜索结果的最佳体系结构?

然后,我能想到的两个选项:

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

2°:搜索方法没有任何返回类型,但是一旦搜索过程结束,就会引发一个事件并使用其视图模型最终值在事件参数中传递,以便调用代码使用它。 (并最终被视图消耗)

对此有何看法?

编辑:当然,用溶液1°,我指的由搜索结果“占位”返回的对象WPF数据绑定对象

+0

传递一个回调函数,当搜索完成后,将更新视图。 – 2010-08-11 18:26:35

回答

0

我会拿数据的优势,并结合你的绑定搜索结果呈现控件添加到可观察的搜索结果集合中,并从后台工作线程更新ViewModel中的集合。然后它不需要你的代码中有任何回调或更新消息,它只是像你期望的那样利用WPF中的管道。

+2

从后台线程对INotifyPropertyChanged属性或INotifyCollectionChanged集合(如ObservableCollection)执行更新会引发异常,除非您使用Dispatcher.Invoke之类的东西,这本质上是为UI线程创建回调。除非您在DoWork期间进行多个独立更新,否则只需将更改应用于RunWorkerCompleted回调即可更直接。 – 2010-08-11 18:37:48

+0

我的回答可能会更清楚。我不会实际更新后台工作线程的集合。我会让后台工作线程从搜索结果中收集结果,然后我将这些结果放入ViewModel中View绑定的可观察集合中。这样,用户界面在获得搜索结果的同时保持响应,我们并不需要担心回调。有很多方法可以给这只猫蒙皮,比你指出的更危险。 – 2010-08-12 17:05:00

+0

backgroundworker有一个在主线程中引发的事件,因此:更新视图模型值时没有问题。实际上,我的问题更多的是关于是否使用WPF管道进行这种“延迟反应”,或者在收到数据时手动将数据推送到视图模型,我相信Dave的回答很简单。至少,这证实了我自己的感觉,因为没有人指出这是一个异端,这是我要采取的道路;)谢谢:) – 2010-08-15 09:13:04

2

如果您使用BackgroundWorker,则会为您完成设计模式。请致电DoWork事件处理程序的搜索方法,并把结果在在通过了DoWorkEventArgsResults财产。

更新与在RunWorkerCompleted事件处理结果的UI(他们将在RunWorkerCompletedEventArgs对象的Results属性)。

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

0

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

IsBusy属性是我在所有视图模型的基类中所拥有的。它是一个布尔值,如果一个视图想显示某种等待控件(如微调控件或其他),那么这个视图可以绑定到该布尔值上。

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

所以效果是,当视图第一次获取数据时,它立即返回,但得到空值。然后几秒钟后,它获得实际数据。在那段时间里,用户界面很快响应。而且,如果用户界面想让用户知道它在后台工作,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"); 
    } 

}