如何提醒ViewModel模型中的变化...或者我应该如何?

我正在浏览一些MVVM文章,主要是这个和这个。

我的具体问题是: 如何将模型更改从模型传递给ViewModel?

在乔希的文章中,我没有看到他这样做。 ViewModel总是要求模型的属性。 在Rachel的例子中,她的模型实现了INotifyPropertyChanged ,并且引发了模型中的事件,但它们被视图本身所使用(请参阅她的文章/代码以获取更多关于她为什么这样做的更多细节)。

我看不到任何模型提示ViewModel对模型属性所做更改的示例。 这让我担心可能因为某种原因没有完成。 是否有模式提醒ViewModel模型中的变化? 这似乎是必要的,因为(1)对于每个模型可以有多于1个ViewModel,并且(2)即使只有一个ViewModel,对该模型的某些操作可能导致其他属性被改变。

我怀疑可能会有“你为什么要这么做?”的形式的答案/评论。 评论,所以这里是我的程序的描述。 我是MVVM的新手,所以也许我的整个设计都有问题。 我将简要描述一下。

我正在编写一些比“客户”或“产品”类更有趣的东西(至少对我来说!)。 我正在编程BlackJack。

我有一个没有任何代码的视图,只是依赖于绑定ViewModel中的属性和命令(参见Josh Smith的文章)。

无论是好还是坏,我都认为模型不应仅仅包含诸如PlayingCardDeck之类的类,而且还包含保持整个游戏状态的BlackJackGame类,并且知道玩家何时破产,庄家必须画牌,以及玩家和经销商当前得分是多少(小于21,21,胸围等)。

BlackJackGame我公开了像“DrawCard”这样的方法,并且在我看来,当绘制卡片时,应该更新CardScoreIsBust等属性,并将这些新值传递给ViewModel。 也许这是错误的想法?

有人可能会认为ViewModel称之为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事件附加到它的情况,那么您可以使用Messaging系统,例如Prism的EventAggregator或MVVM Light的Messenger

我在我的博客上简要概述了消息传递系统,但总而言之,任何对象都可以广播消息,任何对象都可以订阅以收听特定的消息。 因此,您可能会从一个对象广播PlayerScoreHasChangedMessage ,而另一个对象可以订阅以侦听这些类型的消息,并在它听到一个消息时更新它的PlayerScore属性。

但我认为这不是您所描述的系统所需要的。

在理想的MVVM世界中,您的应用程序由您的ViewModel组成,而您的模型只是用于构建应用程序的模块。 它们通常只包含数据,所以不会有像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 ,但为了简单起见,我将其忽略了)


简答:这取决于具体情况。

在你的例子中,模型正在“自己”更新,当然这些变化需要以某种方式传播给观点。 由于视图只能直接访问视图模型,这意味着模型必须将这些更改传递给相应的视图模型。 这样做的机制当然是INotifyPropertyChanged ,这意味着你会得到这样一个工作流程:

  • Viewmodel被创建并包装模型
  • Viewmodel订阅模型的PropertyChanged事件
  • Viewmodel被设置为视图的DataContext ,属性被绑定等
  • 查看触发器对viewmodel的操作
  • Viewmodel在模型上调用方法
  • 模型更新自己
  • Viewmodel处理模型的PropertyChanged并引发它自己的PropertyChanged作为响应
  • 视图反映其绑定的变化,关闭反馈循环
  • 另一方面,如果你的模型包含很少(或没有)业务逻辑,或者由于某种其他原因(例如获得事务性能力),你决定让每个视图模型“拥有”它的包装模型,然后所有对模型的修改都会通过视图模型如此的安排将不是必需的。

    我在这里描述了另一个MVVM问题中的这种设计。


    您的选择:

  • 实施INotifyPropertyChanged
  • 活动
  • 带代理操作器的POCO
  • 正如我所见, INotifyPropertyChanged是.Net的基础部分。 即它在System.dll 。 在你的“模型”中实现它类似于实现事件结构。

    如果你想要纯粹的POCO,那么你必须通过代理/服务来操作你的对象,然后通过监听代理来告诉ViewModel变化。

    就个人而言,我只是松散地实施INotifyPropertyChanged,然后使用FODY为我做脏活。 它看起来和感觉POCO。

    一个例子(使用FODY到IL编织PropertyChanged提高者):

    public class NearlyPOCO: INotifyPropertyChanged
    {
         public string ValueA {get;set;}
         public string ValueB {get;set;}
    
         public event PropertyChangedEventHandler PropertyChanged;
    }
    

    那么你可以让你的ViewModel监听PropertyChanged的任何改变; 或财产特定的变化。

    INotifyPropertyChanged路由的美妙之处在于,您将它与Extended ObservableCollection链接起来。 所以你把你附近的poco对象转储到一个集合中,然后听集合......如果有任何变化,在任何地方,你都会了解它。

    老实说,这可能会加入“为什么不是由编译器自动处理的INotifyPropertyChanged”讨论,它可以解决以下问题:c#中的每个对象都应该有设施来通知它的任何部分是否已更改; 即默认实现INotifyPropertyChanged。 但是它并不是最好的路线,只需要最少的努力就是使用IL编织(特别是FODY)。

    链接地址: http://www.djcxy.com/p/20279.html

    上一篇: How to alert ViewModel of changes in Model... or should I?

    下一篇: Good examples of MVVM Template