4

私はC#でMVVMアプリケーションに取り組んできましたが、ViewダイジェストのViewModelsのコレクションを操作するときに、一貫していくつかの問題が発生しました。具体的には、それらはすべて、モデルがViewModelのプライベートメンバーであるという問題に関連する傾向があります。

この例は、(ビューからの要求に応じて)新しいViewModelを作成することです。いくつかの前文(私を助けるためにこれらを必要としないかもしれませんが)のために、ここにサンプルのModelクラスとViewModelクラスがあります:

Private Class Model()
{
    public string Name { get; set; }
}

Public Class ViewModel()
{
    Private Model _Model;

    Public Void ViewModel(Model model)
    {
        _Model = model;
    }

    Public String Name
    { 
        get
        {
            return _Model.Name;
        }
        set
        {
            _Model.Name = value;
        }
    }
}

モデル全体がViewModelのパブリックメンバーとして直接公開されることはありません。MainWindowViewModelは、Models(プライベート、ビューはこれらを表示できません)およびViewModels(ビューダイジェスト用にパブリック)のコレクションを処理します。

Public Class MainWindowViewModel
{
    Private List<Model> _NamesModel;
    Private ObservableCollection<ViewModel> _NamesViewModel;

    Public Void MainWindowViewModel()
    {
        //Lets pretend we have a service that returns a list of models
        _NamesModel = Service.Request();
        foreach(Model model in _NamesModel)
        {
            ViewModel viewmodel = new ViewModel(model);
            _NamesViewModel.Add(viewmodel);
        }
    }

    Public ObservableCollection<ViewModel> NamesViewModel
    {
        get
        {
            return _NamesViewModel;
        }
    }
}

これが前文ですが、問題があります。新しいViewModelを追加するにはどうすればよいですか?ビュー内のメソッドは新しいViewModelを作成し、それを設定しますか?純粋主義者である私は、ビューがモデルを作成または設定することをまったく許可されるべきではないと想定しています。私のViewModelには、何も受け入れない(つまり、基になるモデルがない)コンストラクターを含める必要がありますか?代わりに、入力するブランクを作成しますか?

これらの種類の問題は、「純粋な」MVVMアプローチを考え出し続けます。モデル(削除の準備ができているなど)を内部モデルと比較するパブリックメソッド(bool compare(Model model))をViewModelに作成する必要がありました。モデルが公開されている(純度が高い)場合は、モデルに接続されているViewModelを見つけるなどの作業がはるかに簡単になります。

4

2 に答える 2

2

私はそれらの問題のいくつかに同情することができます。私は最近、同様の質問が頻繁に出てくるMVVMアプリケーションを作成しました。秘訣の1つは、モデルインスタンスを担当するクラスを(確実に)決定することです。MainWindowViewModelにしますか?またはあなたのNameViewModel?これらのクラスの両方でモデルを作成/削除する責任を共有したくありません。かなりのロジスティックの悪夢があります。

第二に、「純粋な」MVVMアプローチでさえ、モデルを公開できないことを示していません。あなたはそうすることであなたに多くの頭痛を救うだろうとあなた自身に言いました:それをしてください。MVVMは、ViewModelにビューの知識/アクセスがないことのみを指示します。INotifyPropertyChangedインターフェイスを使用してモデルを実装し、モデルのプロパティに直接バインドする「公式」MVVMの例は数多くあります。

個人的には、NameModelの制御をNameViewModelに指示すると思います。これは、NameModelsのリストをMainWindowViewModelから完全に削除する必要があることを意味します。NameViewModelに、モデルを受け取るオプションのコンストラクターを指定する場合は、それでも問題ありません。

私はこのアプローチのファンです:

public NameViewModel : ViewModelBase
{
    public NameModel Model
    { 
        get { /* get stuff */ }
        set { /* set stuff */ }
    } 

    // Default constructor creates its own new NameModel
    public NameViewModel()
    {
        this.Model = new NameModel();
    }

    // Constructor has a specific model dictated to it
    public NameViewModel(NameModel model)
    {
        this.Model = model;
    }

    //Model wrapper properties
    public String Name
    { 
        get { return Model.Name; }
        set { Model.Name = value; }
    }
}

と...

public class MainWindowViewModel
{
    Private ObservableCollection<ViewModel> _NameViewModels;

    Public Void MainWindowViewModel()
    {
        //Lets pretend we have a service that returns a list of models
        var nameModels = Service.Request();
        foreach(Model model in nameModels)
        {
            ViewModel viewmodel = new NameViewModel(model);
            NameViewModel.Add(viewmodel);
        }
    }

    Public ObservableCollection<ViewModel> NameViewModels
    {
        get
        {
            return _NameViewModels;
        }
    }
}

このように、MainWindowViewModelはモデルの完全に別個のコピーを保持しません。NameViewModelsのみを追跡します。各NameViewModelは、独自の基礎となるモデルを担当しますが、構築中に特定のモデルを渡すためのオプションを利用できるようにします。

于 2012-12-29T13:32:47.640 に答える
1

作成に関連するすべての問題は、ファクトリデザインパターンを導入することで解決できます。工場では、提供されたモデルに基づいてビューモデルを作成します。

public class MainWindowViewModel
{
    private List<Model> _NamesModel;
    private ObservableCollection<ViewModel> _NamesViewModel;
            private IViewModelFactory factory;

    public void MainWindowViewModel(IViewModelFactory factory)
    {
        //Lets pretend we have a service that returns a list of models
        _NamesModel = Service.Request();
        _NamesViewModel = factory.CreateNamesViewModels(_NamesModel);
    }

    public ObservableCollection<ViewModel> NamesViewModel
    {
        get
        {
            return _NamesViewModel;
        }
    }
}

さらに、ビューモデルの依存関係を取り除き、Serviceそれをファクトリ自体に移動することもできます。これにより、モデルをビューモデルに保持する必要性が減ります(ただし、モデルの削除は、より複雑なシナリオでは機能しない場合があります)。

public ObservableCollection<ViewModel> CreateNamesViewModels()
{
    var models = Service.Request();
    return new ObservableCollection(models.Select(m => new ViewModel(m)));
}

また、メインウィンドウビューモデルはcommands、ファクトリを利用して新しいインスタンスを作成することを公開できます。このように、モデルが表示に漏れたり、作成の詳細が公開されたりすることはありません(コマンドによって実際の実装が非表示になるため)。

于 2012-12-29T13:43:39.357 に答える