我正在阅读一些MVVM文章,主要是this和this。
我的具体问题是: 如何将模型更改从模型传递到ViewModel?
在Josh的文章中,我看不到他这样做。ViewModel总是向模型询问属性。在Rachel的示例中,她确实具有模型实现INotifyPropertyChanged,并从模型中引发事件,但是这些事件仅供视图本身使用(有关执行此操作的详细信息,请参阅她的文章/代码)。
INotifyPropertyChanged
我在哪里都看不到模型向ViewModel发出模型属性更改警报的示例。这让我担心也许由于某些原因未完成。 有没有一种模式可以警告ViewModel模型中的更改? 似乎有必要,因为(1)可以想象每个模型有多个ViewModel,并且(2)即使只有一个ViewModel,对模型的某些操作也可能导致其他属性被更改。
我怀疑可能会有“为什么要这样做?”形式的答案/评论。注释,所以这是我的程序的描述。我是MVVM的新手,所以我的整体设计可能有问题。我将简要描述一下。
我正在编写比“客户”或“产品”类更有趣的东西(至少对我而言!)。我正在编程BlackJack。
我有一个View,它没有任何代码,仅依赖于绑定到ViewModel中的属性和命令(请参阅Josh Smith的文章)。
是好还是坏,我把该模型应该不仅包含类,如态度PlayingCard,Deck但也BlackJackGame认为保持整场比赛的状态类的,知道什么时候该玩家已经破产,经销商有画卡,玩家和发牌人当前的得分是多少(小于21、21,半身等)。
PlayingCard
Deck
BlackJackGame
从BlackJackGame我开始,我公开了“ DrawCard”之类的方法,然后想到在绘制卡片时CardScore,IsBust应该更新诸如和的属性,并将这些新值传递给ViewModel。也许那是错误的想法?
CardScore
IsBust
可以采取ViewModel调用该DrawCard()方法的态度,因此他应该知道要求更新分数,并确定自己是否破产。意见?
DrawCard()
在我的ViewModel中,我有逻辑来获取一张扑克牌的真实图像(基于西装,等级)并使之可用于视图。该模型不必为此担心(也许其他ViewModel只会使用数字而不是纸牌图像)。当然,也许有人会告诉我,该模型甚至不应该具有BlackJack游戏的概念,而应该在ViewModel中进行处理?
如果您希望模型向ViewModels发出更改警报,则它们应实现INotifyPropertyChanged,并且ViewModels应订阅以接收PropertyChange通知。
您的代码可能看起来像这样:
// Attach EventHandler PlayerModel.PropertyChanged += PlayerModel_PropertyChanged; ... // When property gets changed in the Model, raise the PropertyChanged // event of the ViewModel copy of the property PlayerModel_PropertyChanged(object sender, PropertyChangedEventArgs e) { if (e.PropertyName == "SomeProperty") RaisePropertyChanged("ViewModelCopyOfSomeProperty"); }
但是通常只有在多个对象将对模型的数据进行更改时才需要这样做,而通常情况并非如此。
如果您遇到的情况是实际上没有引用Model属性将PropertyChanged事件附加到该属性,则可以使用诸如Prism EventAggregator或MVVM Light的消息系统Messenger。
EventAggregator
Messenger
我在博客上对消息传递系统进行了简要概述,但是总而言之,任何对象都可以广播消息,并且任何对象都可以订阅以侦听特定消息。因此,您可以PlayerScoreHasChangedMessage从一个对象广播一个对象,而另一个对象可以订阅以侦听这些类型的消息,并PlayerScore在听到一个消息时更新其属性。
PlayerScoreHasChangedMessage
PlayerScore
但是我认为您所描述的系统不需要这样做。
在理想的MVVM世界中,您的应用程序由ViewModel组成,而Models只是用于构建应用程序的模块。它们通常仅包含数据,因此不会具有诸如DrawCard()(在ViewModel中)的方法。
因此,您可能会拥有简单的Model数据对象,如下所示:
class CardModel { int Score; SuitEnum Suit; CardEnum CardValue; } class PlayerModel { ObservableCollection<Card> FaceUpCards; ObservableCollection<Card> FaceDownCards; int CurrentScore; bool IsBust { get { return Score > 21; } } }
并且您将有一个ViewModel对象,例如
public class GameViewModel { ObservableCollection<CardModel> Deck; PlayerModel Dealer; PlayerModel Player; ICommand DrawCardCommand; void DrawCard(Player currentPlayer) { var nextCard = Deck.First(); currentPlayer.FaceUpCards.Add(nextCard); if (currentPlayer.IsBust) // Process next player turn Deck.Remove(nextCard); } }
(以上对象都应该实现INotifyPropertyChanged,但为简单起见,我省略了)