1

私の質問は: ビューモデルの継承チェーンを管理する方法は?

私の状況:

INotifyPropertyChanged インターフェイスのみを実装する標準のViewModelBaseを使用しています。

さらに、Guid を持つBusinessObjectViewModel、個人のコア データを持つPersonBaseViewModel、顧客関連のものを持つCustomerViewModel 、従業員関連のものを持つEmployeeViewModelがあります。

すべてのビューモデルは確実にモデル オブジェクト (Customer、Employee、PersonBase) をカプセル化します。

  • BusinessObjectViewModel は ViewModelBase から継承します
  • PersonBaseViewModel は BusinessObjectViewModel から継承します
  • CustomerViewModel は PersonBaseViewModel から継承します
  • EmployeeViewModel は PersonBaseViewModel から継承します

モデルは、コンストラクターを介してビューモデルに入ります。

コンストラクター チェーンを使用する場合 (すべてのビューモデルが基本コンストラクターを呼び出します)、すべてのビューモデルには、モデルからカプセル化された値を返すモデルがあります。

しかし、すべてのビューモデルにモデル プロパティが必要です。CustomerViewModel の場合、CustomerViewModel に参照があり PersonBaseViewModel に 1 つ、BusinessObjectViewModelに 1 つの同じオブジェクトの参照があります。それは私にはばかげているように聞こえます。

または、上部のビューモデルですべてのプロパティ アクセスをキャストする必要があります。

ps これは私のモデル階層のほんの一部です。

前もって感謝します。

4

3 に答える 3

2

IMO の最も簡単な答えは Generics を使用することです。

public abstract class ViewModelBase<TModel>  TModel : class{
    public TModel Model { get; protected set; }
}

.net タイピング システムは、TModel が Person、Customer、またはその他のものであることを、キャストせずに認識します。

さらに必要な場合、または助けが必要なコードを投稿したい場合はお知らせください。そうです、最初はスーパータイプの階層を正しく設定するのは難しい場合があります。

HTH、
ベリル

于 2012-05-23T18:24:48.763 に答える
1

BusinessObject クラスと Person クラス (および対応する VM) が抽象的である場合、次のように適切なモデルにアクセスできます。

public abstract class BusinessObjectViewModel : ViewModelBase
{
    protected abstract BusinessObject BusinessObject { get; }

    protected BusinessObject Model { get { return this.BusinessObject; } }
}

public abstract class PersonViewModel : BusinessObjectViewModel
{
    protected abstract Person Person { get; }

    protected new Person Model { get { return this.Person; } }

    protected override sealed BusinessObject BusinessObject
    {
        get { return this.Model; }
    }
}

public class CustomerViewModel : PersonViewModel
{
    protected new Customer Model { get; set; }

    protected override sealed Person Person
    {
        get { return this.Model; }
    }
}

public class EmployeeViewModel : PersonViewModel
{
    protected new Employee Model { get; set; }

    protected override sealed Person Person
    {
        get { return this.Model; }
    }
}

このように、派生したすべての VM クラスは、抽象プロパティを実装することでベース VM Model プロパティの値を提供し、基本クラスの Model プロパティを非表示にするため、すべての VM は適切な型の Model プロパティで動作します (したがって、キャストは必要ありません)。

このアプローチには、次の利点と欠点があります。

利点:

  • キャストは含まれません。

欠点:

  • 基本クラス (BusinessObjectViewModel および PersonViewModel) が抽象である場合にのみ機能します。これは、派生クラスによって実装され、Model インスタンスをこれらの基本クラスに提供する抽象プロパティが存在する必要があるためです。
  • コンストラクター チェーンは基本クラスから最も派生したクラスに移動するため、基本クラス コンストラクターでモデル プロパティにアクセスしないでください。最も派生したクラス コンストラクターは Model を設定するため、基本クラスのコンストラクターはそれを確認するために早期に呼び出されます。これは、Model をコンストラクターを介してパラメーターとして渡すことで回避できます。
  • BusinessObject および Person プロパティは、派生クラスからは不要です。ここで EditorBrowsableAttribute が Intellisense に役立つ可能性がありますが、コードが別の Visual Studio ソリューションの別のアセンブリによって使用されている場合のみです (これは Visual Studio 固有の動作です)。
  • パフォーマンス。基本クラスが Model にアクセスするとき、コードは一連の仮想プロパティを通過します。ただし、実装された抽象プロパティは封印されているため、仮想テーブルのルックアップでパフォーマンスがそれほど低下することはありません。
  • うまくスケーリングしません。深いクラス階層の場合、コードには多くの不要なメンバーが含まれます。

別のアプローチは次のとおりです。

public class BusinessObjectViewModel : ViewModelBase
{
    protected BusinessObject Model { get; private set; }

    public BusinessObjectViewModel(BusinessObject model)
    {
        this.Model = model;
    }
}

public class PersonViewModel : BusinessObjectViewModel
{
    protected new Person Model { get { return (Person)base.Model; } }

    public PersonViewModel(Person model)
        : base(model)
    {
    }
}

public class CustomerViewModel : PersonViewModel
{
    protected new Customer Model { get { return (Customer)base.Model; } }

    public CustomerViewModel(Customer model)
        : base(model)
    {
    }
}

public class EmployeeViewModel : PersonViewModel
{
    protected new Employee Model { get { return (Employee)base.Model; } }

    public EmployeeViewModel(Employee model)
        : base(model)
    {
    }
}

利点:

  • 基本クラスは抽象である必要はありません。
  • モデルには、基本クラスのコンストラクターを介してアクセスできます。
  • 不要な追加プロパティはありません。

欠点:

  • 鋳造。

この分析に基づいて、私は 2 番目のオプションを使用します。その唯一の欠点であるキャスト パフォーマンスを修正することは、WPF コンテキストでは目立たない不要なマイクロ最適化になるからです。

于 2012-05-23T20:28:12.473 に答える
0

ViewModel で Model プロパティを公開するだけの場合は、ViewModel で Model プロパティを再宣言して公開する必要はありません。私は通常、基になる Model オブジェクトを ViewModel のプロパティとして公開します。あなたの場合、たとえば EmployeeViewModel には次のものがあります。

private Employee _MyEmployee;
public Employee MyEmployee {
get
{
return _MyEmployee;
}
set
{
_MyEmployee = value;
NotifyPropertyChanged(x=>x.MyEmployee);
}

次に、ViewModel で公開されている MyEmployee プロパティを介して、View を Employee プロパティにバインドできます。私が理解している限り、VM でモデル プロパティを再宣言またはラップする唯一のケースは、ビューに表示するデータ操作を行う必要がある場合です。

于 2012-05-23T16:42:20.413 に答える