Wpf MVVM与多线程

Wpf MVVM与多线程,wpf,multithreading,mvvm,Wpf,Multithreading,Mvvm,好的,目前仍以MVVM为重点,有少数情况下可能会发生线程: 通常,为了简单起见,我们有一个模型类、ViewModel类和View类。 该模型具有一个集合和一个字符串属性 1) 用户触发长时间运行的后台任务。视图触发ViewModel。可以通过ViewModel轻松管理,例如使用BackgroundWorker 2) 线程更新模型,视图模型由模型通知更改 前面我们讨论了使用INotifyChanged通知从模型到视图模型的更改。DependencyProperty系统似乎为您将这些封送到正确的线程

好的,目前仍以MVVM为重点,有少数情况下可能会发生线程:

通常,为了简单起见,我们有一个模型类、ViewModel类和View类。 该模型具有一个集合和一个字符串属性

1) 用户触发长时间运行的后台任务。视图触发ViewModel。可以通过ViewModel轻松管理,例如使用BackgroundWorker

2) 线程更新模型,视图模型由模型通知更改

前面我们讨论了使用INotifyChanged通知从模型到视图模型的更改。DependencyProperty系统似乎为您将这些封送到正确的线程

对于可观察的收集,这不起作用。因此,我的模型的公共面应该是单线程的(不喜欢,为什么模型应该知道线程)还是在ViewModel中复制模型的某些部分(例如上面的集合),以确保在正确的线程上进行修改

我想我已经回答了我自己的问题。也许不是。我的模型确实知道线程,所以也许使用科林之前提出的IMarshalInvoker想法来标记线程是礼貌的做法


我的一些问题是,我认为MVVM是另一个MVC变体,在历史上,我非常乐意使用像MVP、MP、MVC这样的术语,因为我知道在V端上使用GUI技术(通常是WiFrm)。当我说MVVM时,我特别是在寻找关于WPF和WPF特有缺点的实用建议。我希望这能解释我的问题的性质以及我问这些问题的原因。

我认为在您的模型中全力实现集合作为
可观察集合是一个不好的主意,因为这会以一种只对WPF有用的方式“污染”您的模型

INotifyPropertyChanged
正常,因为:

  • 在很多情况下,拥有“监听”功能是很有用的
  • 它可以从几乎任何.NET代码中使用,而不仅仅是WPF
  • 如果您想序列化模型,它不会给您带来任何麻烦
因此,我建议不要让您的模型知道线程。让您的ViewModel了解线程,如下所示:

class Model {
    List<Widget> Widgets { get; private set; }
}

class ModelViewModel {
    ObservableCollection<Widget> Widgets { get; private set; }

    ModelViewModel(Model model) {
        this.Widgets = new ObservableCollection<Widget>(model.Widgets);
    }
}

最后,您需要使
observetecollection
能够很好地从工作线程进行更新。这是WPF中一个非常常见的问题,我建议您参考这个问题的答案来寻求解决方案:。

好的,我想我理解您的意思,所以让我给您介绍一个小场景,您能描述一下上面的内容是如何适合的吗?我将尽量不把我的解决方案强加给它。我们有上面的模型和ModelViewModel(模型的ViewModel)。我有一个组件,它正在侦听有关新窗口小部件的新闻,当它收到新闻时,它会在自己的线程(即,不是UI线程)上引发一个事件。在该组件中,我在哪里布线?对我来说,这听起来像是模型材料,但从上面看,我们将使用ViewModel?@Ian:如果组件是您业务逻辑的一部分,那么您可以按照您的建议在
Model
中设置挂钩,或者在您的应用程序中设置一个充当
Model
存储库的“服务”。在这种情况下,它将为
Model
s提供CRUD方法,因此当您想要添加
Widget
时,您将在服务上调用
UpdateModel(Model)
,服务将触发组件将钩住的
ModelUpdated
事件(这种方法是棱镜风格的)。无法确定哪一个更适合您的特定场景。好吧,那么在该示例中,ViewModel将订阅ModelUpdated,并且无论在哪个线程上触发它,都会将其封送回正确的线程

历史上,我有一个中央消息总线事件,所有组件都将使用它进行通信。因此,我的模型可能会得到一个新的小部件,然后在总线上生成一条新的小部件消息,该消息将由UI使用。我想这就是我要去的地方。我用过Prism,但我没有信心能推断出我对它的理解,我将去构建一个新的Prism测试应用程序:)Thanks@Ian:ViewModel可能不需要封送任何内容。即使它决定更新的模型数据应该覆盖用户正在处理的所有内容,它也可以简单地用一个新集合替换它公开的
ObservableCollection
。这不会遇到“修改现有可观察集合”的问题,因此不需要特殊的线程代码。只需找到一个显示MVVM的图表,其中包含一个附加的控制器类,这与我一开始想的差不多:)
ModelViewModel(Model model) {
    this.Widgets = new ObservableCollection<Widget>(model.Widgets);
    this.Widgets.CollectionChanged += this.PropagateChangesToModel;
}

void PropagateChangesToModel(object sender, NotifyCollectionChangedEventArgs e) {
    // do what the name says :)
}