0

我正在创建一个与一个或多个服务通信的简单网络应用程序,因此我计划使用一些队列(用于传出消息和传入消息)、一个表、一个包含每个活动连接状态的列表等:在其他换句话说,这些是确保应用程序本身运行所需的数据结构。

此应用程序还必须配备图形界面,显示应用程序本身的部分内部功能:例如,队列的填充状态、连接的状态(检测到的速度等)等。根据Model-View-ViewModel 模式,模型由要在 GUI 中显示的数据组成:在此应用程序中,上述数据结构表示模型。换句话说,Model实现了应用程序的业务逻辑。

ViewModel应该实现INotifyPropertyChanged接口以便通知View发生了变化,但是 Model 如何与 ViewModel 通信呢?看完这篇文章,我意识到INotifyPropertyChanged接口是由模型实现的。这个答案解释了一点,但它让我有点困惑:

INotifyPropertyChanged - 应该进入 ViewModel 和 Model(如果需要)

为什么,如果需要?我应该什么时候实现这个接口?我什么时候不应该实施它?

此外,Dictionary没有实现INotifyPropertyChanged接口:如果我使用它,我应该用实现这个接口的类来包装它吗?

最后,模型应该是只读的,这意味着用户不能使用 GUI 更改内部数据结构的内容。如何做到这一点?

4

3 回答 3

2

how does the Model to communicate with the ViewModel

任何你想要的方式。在我们编写的大多数应用程序中,视图模型都会调用业务逻辑层(模型)。但是,如果您需要在模型更改时立即通知视图模型(事件),您可以在模型上实现 INotifyPropertyChanged。或者您可以简单地让视图模型订阅模型上的事件。

Moreover, the Dictionary does not implement the INotifyPropertyChanged interface: if I use it, should I wrap it with a class which implements this interface?

您只需要让视图模型实现 INotifyPropertyChanged。视图模型(字典)中的属性将简单地调用 NotifyPropertyChanged(或任何您的实现看起来像)。

Finally, the model should be read-only, meaning that the user does not be able to change the contents of internal data structures using the GUI. How to accomplish this?

不要向用户提供让他们更改数据的功能。以一种方式进行绑定,或者干脆不为他们提供进行更改的 API。

于 2012-08-16T23:48:11.050 回答
1
  1. INotifyPropertyChanged 主要由 ViewModel 类实现。这是为了方便数据绑定,以便视图中绑定到 ViewModel 属性的 UI 控件将在属性被修改时更新。
    在 MVVM 设计模式中,关系非常简单并且是单一方向的。View 知道它是 ViewModel,而 ViewModel 知道 Model。如果模型更新了,视图模型需要以某种方式知道,以便它可以反映更新并将其传播到视图。一种方法是让 Model 实现 INotifyPropertyChanged 并让 ViewModel 实现相应的事件处理程序。如果所有更改都是从 UI 驱动并被推送回模型,那么这可能没有必要。

  2. 你不能真正绑定到字典。如果这适用于您的情况,则使用 ObservableCollection 将是理想的。或者,您可以按照以下方式查看实施 Observable Dictionary:http: //drwpf.com/blog/2007/09/16/can-i-bind-my-itemscontrol-to-a-dictionary/

  3. MVVM 提供了 Model 与 View 的分离,因此 View 与 Model 之间应该没有直接关系。ViewModel 的实现控制着什么,如果有任何东西会被写回你的模型。

于 2012-08-16T23:41:36.987 回答
0

INotifyPropertyChanged(INPC)永远不应出现在模型中,除非模型也是 ViewModel(即您没有“模型”)。INPC 应该只在视图模型中。

模型应该对视图模型一无所知,因此永远无法与之通信。只有视图模型可以与模型通信。

从 UI 的角度来看,只有视图模型对数据做任何事情;所以,如果你希望模型是“只读的”,那么就不要在视图模型中实现它。

绑定将使用视图模型完成,在这种情况下不要使用 Dictionary(除非您想编写代码来包装它以便绑定它)。如果 Dictionary 在模型中,那么您应该在视图模型中“包装”它——围绕集合编写一个可观察的包装器是相当简单的。您的视图模型很可能不会处理键/值对——它应该处理 UI 可以处理(并绑定到)的平面。

更新
为数据绑定引入了 INPC。它将视图与特定的具体类解耦,因此它只需要了解 INPC(注意解耦的方向)。就 MVVM 而言,这将视图与视图模型解耦,在 PM 的情况下,这可以将视图与演示者解耦,在 MVC 的情况下,这可以将视图与控制器解耦,在 MVP 的情况下,这可以解耦来自主持人的看法。

数据绑定是一种将数据绑定到 UI 元素的技术。它将数据源绑定到目标,以便目标可以请求数据,无论它认为合适,或者源可以推送数据,但它认为合适(取决于绑定的类型——它可以是单向或静态的,限制如何经常会发生获取/推送)。

有时,数据源和目标之间解耦关系的必要性质导致人们相信数据绑定不是 UI 问题,数据绑定可以应用于任何地方。即数据绑定实现与 UI 完全分离。这通常是一个错误。数据绑定将视图与特定类的特定知识解耦(这是基本的分层和避免循环,我不会在这里讨论)。但是,它并没有将视图与数据源完全分离。没有数据源就无法进行绑定——那里仍然存在一定程度的耦合,只是已经减轻了编译时耦合(有助于测试、灵活性、健壮性等,但必须在生产运行时存在. 即,可以在运行时不绑定到 UI 元素的情况下测试 INPC 实现这一事实并不意味着它不依赖于 UI 框架)。视图仍然与数据源松散耦合的事实并不是这种关系中唯一的耦合。数据源通过其 UI 框架松散地(如果不是更松散地)耦合到视图。

每个 UI 框架都有一个限制,即 UI 元素的访问和修改必须在主线程或 UI 线程上完成。(至少在 Windows 上;它可能发生在其他平台上,我只是不精通其他平台)。使用数据绑定,源间接绑定到控件,任何数据更改都会直接更改一个或多个 UI 元素(取决于您可以拥有中介的框架。就像WinRT 中的值转换器,但它们的职责是转换或转换数据)。这意味着数据源需要深入了解它绑定到 UI 以及绑定到什么类型的 UI 框架。这种与 UI 框架的紧密耦合显然将数据源(仍然松散)耦合到 UI。

这意味着 INPC 的任何特定实现都真正绑定到一个且只有一个 UI 框架。该对象不能再在任何地方使用(显然在任何地方都是理想的,通常不可能使任何东西适用于每个场景——这里的重点是在不止一个或两个场景中的高内聚性)。例如,如果在多线程环境中使用 INPC 的实现,那么它需要在发送属性通知之前将数据“编组”回 UI 线程。在 WinForms 中,即 . Control.BeginInvoke,在 WPF 和 Silverlight 中,通过System.Windows.Threading.Dispatcher. 在 WinRT 中,这是通过Windows.UI.CoreDispatcher. 在所有情况下,INPC 实现都必须直接耦合到一个 UI 框架。在 Silverlight 的情况下,这是与“桌面”的直接耦合Dispatcher或 Windows Phone Dispatcher

质量指标包括凝聚力等概念。内聚度是衡量两个代码单元相关程度的指标。由于支持特定 UI 框架所需的所有基础设施的性质,由 UI 以外的其他东西使用的 INPC 实现,虽然可能能够在 UI 之外使用,但内聚性较低,因为所有不会使用与 UI 框架相关的代码。即,与 UI 完全分离需要承担太多责任。是的,您可以在任何地方使用实现 INPC 的对象并且从不使用该PropertyChanged事件,但是您的凝聚力很低(被认为是不好的)。

如果我在我的模型中实现了 INPC,并且我想将该模型与我的 UI 和我的 WCF 或 Web 服务后端一起使用,我要么不能,要么我的后端将不得不参考一些 UI 框架。如果我想在另一种类型的 UI 中使用该模型,我不能,因为 INPC 实现依赖于一个特定的 UI 框架。我不得不写另一个“模型”;在这一点上,它显然是一个“视图模型”。

INPC 本身并不绑定到特定的 UI 框架(也不应该如此)。这导致了一种误解,即 INPC 可以在任何地方使用。 的,它缺乏与高级命名空间的耦合意味着它可以,但是 INPC 的压倒性使用是当目标是 UI 时。我会挑战 INPC 的任何其他不涉及 UI 作为真正“绑定”的用途。与任何其他工具一样,您可以滥用它来获得有用的结果。INPC用于投影数据,可用于转换数据等;但我相信这些是对 INPC 的滥用,并且确实超出了这个问题的重点......

于 2012-08-17T00:35:53.993 回答