プレゼンテーション ロジック層 (PLL) には、ビジネス ロジック層 (BLL) で定義された /extend インターフェイスを実装するいわゆる「ビュー モデル」クラスがあります。
namespace BLL.Abstract.POCO
{
// also implemented in data access layer (DAL) by data model entities
public interface ISomeDomainModelEntity
{
string Name { get; set; }
string Description { get; set; }
}
}
namespace PLL.Abstract.ViewModels
{
public interface ISomeDomainModelEntityViewModel
: ISomeDomainModelEntity, INotifyPropertyChanged
{
bool IsSelected { get; set; }
}
}
namespace PLL.Concrete.ViewModels
{
public class SomeDomainModelEntityViewModel
: ViewModelBase, ISomeDomainModelEntityViewModel
{
private string _name;
private string _description;
private bool _isSelected;
public string Name { get { return _name; } set { _name = value; NotifyPropertyChanged(() => Name); } }
public string Description { get { return _description; } set { _description = value; NotifyPropertyChanged(() => Description); } }
public bool IsSelected { get { return _isSelected; } set { _isSelected = value; NotifyPropertyChanged(() => IsSelected); } }
}
}
は、この手の込んだ厳密に型指定された実装ViewModelBase
を可能にする抽象クラスであることに注意してください。INotifyPropertyChanged
上記の実装のIsSelected
プロパティは、明らかにプレゼンテーション レイヤーでのみ必要であり (プロパティを にバインドするItemTemplate
機能を持つリストに表示される数十個のこれらのオブジェクトを視覚化します)、プレゼンテーション ロジックは、ビジネスに戻る前にそれを使用する方法を知っています。ロジック層。ListBox
IsChecked
IsSelected
私が抱えている問題は、「ViewModel」という名前がこれと衝突していることです。
namespace PLL.Abstract.ViewModels // hmmm...
{
public interface ISomeWindowViewModel
{
ObservableCollection<ISomeDomainModelEntityViewModel> SomeItems { get; }
}
}
の実装は、ISomeWindowViewModel
最終的にビューのDataContext
プロパティに割り当てられます。
namespace PLL.Concrete.ViewModels
{
public class SomeWindowViewModel : WindowViewModelBase, ISomeWindowViewModel
{
private readonly ObservableCollection<ISomeDomainModelEntityViewModel> _items;
public SomeWindowViewModel(IView view, ObservableCollection<ISomeDomainModelEntityViewModel> items)
: base(view)
{
_items = items;
}
public ObservableCollection<ISomeDomainModelEntityViewModel> SomeItems { get { return _items; } set { _items = value; } }
}
}
namespace PLL.Abstract
{
public abstract class WindowViewModelBase : ViewModelBase
{
public IView View { get; private set; }
protected WindowViewModelBase(IView view)
{
View = view;
View.DataContext = this;
}
}
}
これは、Mark Seeman の.NET での Dependency Injection でDI を WPF に適用する方法について読んだ後に開始した主要なリファクタリングの結果です(これまでのところ非常によく読んでいますが、まだ終わっていません)。ビューの実装をビューモデルに挿入すると、ビューの表示とクローズを処理することで得られた制御/簡素化を理解できます。リファクタリングの前に、DAL および PLL と密接に結合された BLL を使用するアプリケーションが動作していました。現在、BLL には依存関係がまったくありません。これはすばらしいことです。
私はまだコンポジション ルートを (Ninject.Extension.Conventions を使用して) 再構成している最中なので、1 日の終わりには、すべてを機能させるためにいくつかの調整を行う必要があることに気付くかもしれません...痛いかもしれませんが、準備はできています!
したがって、質問は次のとおりです。
- インターフェイスが多すぎるように感じますが、慣例を使用した DI 構成では完全にグリーンです (まあ、DI では完全にグリーンです!)。型がインターフェイスを実装する場合、慣例に従ってICコンテナーを構成するのははるかに簡単に思えます...しかし、これはやり過ぎですか?
- ここで「ViewModel」という用語が乱用されていますか? むしろ、「ViewModel」と「WindowViewModel」の区別は保証されていますか、それとも何か不足していますか? ViewModel が他の ViewModel を「含む」のは正常ですか? そうでない場合、View で DataContext として使用される ViewModel に「WindowViewModel」という名前を付けてもよろしいですか?
- コードベースをめちゃくちゃにしてしまう明らかなアーキテクチャ上の欠陥はありますか? アイデアは、DI を使用して MVVM を可能な限りしっかりと実装することですが、まだ学ぶべきことがたくさんあると思います。
- この投稿をタイプしているときに、昨年のこの質問が「類似の質問」リストに表示され、私の頭の中で物事がさらにぼやけ始めています - 受け入れられた回答と他のコメントは、私が最近読んだものと根本的に矛盾しています. 具体的には、ViewModel クラスに IView 実装を注入する必要があります。この質問/回答 + コメントは正反対のことを言っています。どちらの方法も完全に受け入れられるように見えますが、それは個人的な好みの問題ですか?