11

C#/WPF の MVVM 設計について質問があります。いくつかのデモ アプリケーションを見てきましたが、実際には問題を解決できませんでした。私のアプリケーションは、他のオブジェクトを含むオブジェクトで構成されています。親子関係によく似ています。

私の質問は次のとおりです。

  • children 属性は ViewModel である必要がありますか?
  • その場合、 ViewModels を介して既存の子オブジェクトを含む新しい親オブジェクトを作成するにはどうすればよいですか?

次のシナリオのような sth があります。

class Child {
    string Name;
}

class ChildVM {
    Child _child;
    string Name{return _child.Name;}
}

class Parent {
    string Name;
    List<Child> children;
}

class ParentVM{
    Parent _parent;

    string Name{return _parent.Name;}
    List<ChildVM> children {get;set;}

    ParentVM(Parent p){_parent = p;}
}

void CreateANewParent(){
    List<ChildVM> children = new List<ChildVM>(){new ChildVM(new Child()),...};
    ParentVM parent = new ParentVM(new Parent());
    foreach(ChildVM child in children)
        parent.children.Add(child);
}

ここでの問題は、ParentVM に ChildVM が含まれているが、実際の Parent (ParentVM の内部にある) には ChildVM オブジェクトに含まれる Child オブジェクトがないことです。また、子オブジェクトを複製することは良い考えではないと思います。冗長性につながり、アプリケーションのコンテキストでは、新しい子オブジェクトを作成する必要も可能性もないためです。

また、次のクラス設計についても考えました。

class ParentVM {
    Parent _parent;

    string Name{return _parent.Name;}
    List<Child> children {get{return _parent.Children;}}
}

ただし、これは、ParentVM の Child オブジェクトを操作したい場合、Model を直接操作することを意味します。

一方、(モデル) 親を空白のままにして、ParentVM を使用してデータベースに新しい親を作成することもできます。しかし、これは問題を処理する良い方法ですか?

4

2 に答える 2

16

実際、これを行う適切な方法は、最初に ParentVM を作成するときに、渡された Parent の子を繰り返し処理し、それぞれに対して ChildVM を作成してから、これらの ChildVM オブジェクトを ParentVM の ChildVMs プロパティに追加することです。(そのプロパティを単に「Children」と呼ぶ人もいますが、個人的には、それが Child オブジェクトのコレクションではなく、ChildVM のコレクションであることを明確にするのが好きです。「VM」サフィックスを追加するだけで、それが非常に明確になります。

次に、実際の親の子コレクションへの変更通知をリッスンし、それに応じて ChildVMs コレクションを更新する必要もあります。

そうすれば、Parent->Children->Child のモデルと、ParentVM->ChildVMs->ChildVM の ViewModel を使用できます。これはまさにあなたが望むものだと思います。

また、UI が上記の Name プロパティなど、これらのアイテムのさまざまなプロパティにバインドされている可能性があるため、ParentVM から直接 Parent を公開するだけでなく、ChildVM から直接 Child を公開できるはずだと私は信じています。ただし、MV-VM の純粋主義者は、モデルが変更された場合、UI を変更する必要があるため、UI がモデルについて認識してはならないので、決してこれを行うべきではないと言うでしょう。私の主張は、モデルが変更された場合、まったく同じ理由で ViewModel を変更する必要があるということです。唯一の節約は、同じビューモデルをすべて共有する複数のビューがある場合です。これは、1 か所で変更するだけでよいためですが、現実的には、「名前」のようなものはモデルから「名前」を変更することはありません。 ViewModel であるため、これらの場合はとにかく引数ではありません。

さらに、ビューはモデルによって生成された変更を認識しないため、上記の Name で行っているようにモデル項目に単純に委譲できないという点で、「純粋主義者」の方法で実行するとパフォーマンスのオーバーヘッドがあります。 VM 内に余分な変更通知をすべて追加しない限り、 Name プロパティ。つまり、モデルに 1 つの変更通知があり、唯一の目的は2 番目の変更通知を起動することです。VM で通知を変更し、UI に通知します。ピュア?はい。パフォーマンスに影響しますか? 特に大量の変更が行われており、INotifyPropertyChanged インターフェイスを使用している場合は、変更ハンドラーで文字列比較を実行して、これらすべての変更を検出して委任する必要があるためです。ただし、ParentVM.Parent.Name プロパティに直接バインドすると、UI に通知するためのモデルからの変更通知が既にあり、VM 固有またはビュー固有のものに対して VM をクリーンに保つこともできます。

ただし、表示専用の情報をモデルに配置することは決してありません。それがViewModelの目的です。したがって、たとえば、子が列挙型などに基づいて特定の色を持っている場合、それはモデル自体ではなく ChildVM にあるものであり、モデルにその色を指示するプロパティがある場合、その列挙型のプロパティ、その場合、はい、ChildVM 内のモデルからの変更通知を接続します。(正直なところ、モデルの列挙型にバインドしたまま、UI のカラー コンバーターを介して直接行うこともできます。これは実際にはケースバイケースです。)

HTH、

マーク

于 2011-05-21T02:51:09.377 に答える
1

了解しました。.NETフォーラムからヘルプとアドバイスを受け取りました。ViewModel内のモデルにGet-Methodを提供することで、問題を解決します。したがって、既存のChildVMを使用して新しい親を作成する場合は、ChildVM内で子参照を返し、それらを新しい親に割り当てるだけです。

于 2009-05-13T07:03:53.183 に答える