[解決済み] WPFのMVVM - ViewModelにモデルの変更を警告する方法...すべき?
質問
私はMVVMの記事をいくつか見ていますが、主に この と この .
具体的な質問ですが モデルの変更をモデルからViewModelに伝えるにはどうしたらよいでしょうか?
Joshの記事では、このようなことはしていないようですね。ViewModel は常に Model にプロパティを要求します。Rachel の例では、彼女はモデルに対して
INotifyPropertyChanged
を実装し、モデルからイベントを発生させますが、それはビュー自体で消費するためのものです (なぜこれを行うかについての詳細は、彼女の記事/コードを参照してください)。
モデルがモデルプロパティへの変更を ViewModel に警告する例はどこにも見当たりません。 これは、おそらく何らかの理由で行われていないのではと心配しています。 モデルの変更をViewModelに警告するためのパターンはありますか? (1) 各モデルには1つ以上のViewModelがあると考えられるし、(2) ViewModelが1つであっても、モデルに対する何らかのアクションによって他のプロパティが変更されるかもしれないので、必要だと思われる。
なぜそんなことをしたいんだ」というような回答やコメントがあるかと思いますので、ここで私のプログラムの説明をします。 私はMVVMの初心者なので、もしかしたら私の全体の設計に欠陥があるかもしれません。 簡単に説明します。
私は、quot;Customer" や "Product" クラスよりも面白い(少なくとも、私にとって!)ものをプログラミングしています。 私はBlackJackをプログラミングしています。
私は、背後にコードを持たず、ViewModelのプロパティとコマンドへのバインディングにのみ依存するViewを持っています(Josh Smithの記事を参照ください)。
良くも悪くも、私はモデルには以下のようなクラスだけでなく
PlayingCard
,
Deck
のみならず
BlackJackGame
クラスはゲーム全体の状態を保持し、プレイヤーがバストになったとき、ディーラーがカードを引かなければならないとき、そしてプレイヤーとディーラーの現在のスコア(21未満、21、バストなど)を知っています。
から
BlackJackGame
DrawCard" のようなメソッドを公開していますが、カードが引かれたときに、次のようなプロパティが表示されることを思いつきました。
CardScore
とか
IsBust
は更新され、これらの新しい値が ViewModel に伝達される必要があります。おそらくそれは誤った考えなのでしょうか?
ViewModel が
DrawCard()
メソッドを呼び出したので、彼は更新されたスコアを要求し、バストであるかどうかを見つけるために知っているはずです。 意見は?
私のViewModelでは、トランプの実際の画像(スーツ、ランクに基づく)を取得し、それをビューで利用できるようにするロジックがあります。モデルはこれとは関係ないはずです (おそらく他の ViewModel は、トランプ画像の代わりに数字を使用するだけでしょう)。 もちろん、モデルはBlackJackゲームの概念さえ持つべきでなく、ViewModelで処理されるべきであると私に言う人もいるでしょう?
どのように解決するのですか?
ViewModelsに変更を通知する場合、Modelsに実装された 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");
}
しかし、通常これは、複数のオブジェクトがモデルのデータに変更を加える場合にのみ必要で、通常はそうではありません。
もし、PropertyChanged イベントをアタッチするために、実際にモデルのプロパティへの参照を持っていないようなケースがあれば、Prism の
EventAggregator
や MVVM Light の
Messenger
.
私の場合は
メッセージングシステムの簡単な概要
に書いていますが、要約すると、どんなオブジェクトでもメッセージをブロードキャストすることができ、どんなオブジェクトでも特定のメッセージをリスニングするためにサブスクライブすることができる、ということです。つまり、例えば
PlayerScoreHasChangedMessage
をブロードキャストすると、別のオブジェクトがそのようなメッセージを受信するようにサブスクライブして、そのオブジェクトの
PlayerScore
プロパティを更新します。
しかし、あなたが説明したシステムには、これは必要ないと思います。
理想的なMVVMの世界では、アプリケーションはViewModelsで構成され、Modelはアプリケーションを構築するために使用されるブロックに過ぎません。モデルは通常、データのみを含むので、以下のようなメソッドを持ちません。
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
を実装する必要がありますが、簡略化のため省きました)
関連
-
[解決済み】エラー。「戻り値を変更できません」 C#
-
[解決済み】5.7.57 SMTP - MAIL FROMエラー時に匿名メールを送信するためにクライアントが認証されない
-
[解決済み】ファイルへの読み書きの際に共有違反のIOExceptionが発生する C#
-
[解決済み】URLから画像をダウンロードする方法
-
[解決済み】名前 'ViewBag' が現在のコンテキストに存在しない - Visual Studio 2015
-
[解決済み] なぜList<T>を継承しないのですか?
-
[解決済み】INotifyPropertyChangedとViewModelのDependencyPropertyの比較
-
[解決済み] MVVMを使ったwpfのダイアログの良し悪しは?
-
[解決済み] MVVMテンプレートの好例
-
[解決済み] Android MVVM ViewModelでContextを取得する方法
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み] エンティティタイプ ApplicationUser は、現在のコンテキストのモデルの一部ではありません。
-
[解決済み】トランスポート接続からデータを読み取れない:既存の接続は、リモートホストによって強制的に閉じられました。
-
[解決済み】C# - パスに不正な文字がある場合
-
[解決済み】MetadataException: 指定されたメタデータ・リソースをロードできない
-
[解決済み] EntityTypeにキーが定義されていないエラー
-
[解決済み】ファイルへの読み書きの際に共有違反のIOExceptionが発生する C#
-
[解決済み】C#のequal to演算子でtextとvarcharのデータ型は互換性がない
-
[解決済み】WSACancelBlockingCallの例外について
-
[解決済み】URLから画像をダウンロードする方法
-
[解決済み】Microsoft.Extensions.LoggingからILoggerを解決することができない