3

パッシブ ビュー パターンを使用して MVP トライアドを実装しました。つまり、ビューには単純なゲッターとセッターしか含まれていません。ただし、ビュー データとモデル データの分離に問題があります。特に、ビューステートの変更を処理する場合。

トライアドは、ユーザーがリストからパーツを選択できるようにするために使用されます。パーツのリストはモデルによって提供され、各パーツは一意の ID によって一意に識別されます。

パーツが次のようになっているとします。

class Part
{
    int ID; // this code uniquely identifies the part within the model
    String partCode;
    String description;
    double voltage;
}

ビューはユーザーにリストを表示し、パーツを選択できるようにします

リストは DataGridView に表示され、パーツは dataGridView の行をクリックして選択されます。

ID はユーザーに表示されず、電圧も表示されないため、モデルは partCode と説明のみを含む DataTable を作成します。この DataTable は、プレゼンターによって、DataGridView の DataSource プロパティにマップされるビューのプロパティに割り当てられます。

class Presenter
{
    IView _view;
    IModel _model;

    //...///

    _view.Data = _model.GetFilteredData();
}

class Model
{
    public DataTable GetFilteredData()
    {
        // create a DataTable with the partCode and Description columns only
        // return DataTable
    } 
}

class View  //winform
{
      public DataTable Data
      {
          set 
          {
              this.dataGridView.Source = value;
          }
      }
}

ここまでは順調ですね。View は、フィルター処理されたデータを DataGridView に表示します。

私が抱えている問題は、ユーザーが選択した部分を返すことです。

一意の ID は表示されず、他の情報が一意であることを保証できないため、ビューは一意の ID を認識しません。したがって、選択されたパーツを一意に識別することはできません。

基本的に、他のデータを使用するコンポーネントを使用せずに、ビュー データ (選択した行) をモデル データ (選択した部分) に変換しようとしています。

これまでのところ、次の解決策があります。

1) ID を含む DataTable がビューに渡され、表示がユーザーに表示されないようにフィルター処理されます。選択した行の ID を返すのは簡単です。ここでの問題は、テストされていないロジック (ディスプレイのフィルタリング) でビューを汚染してしまったことです。

2) ビューは行インデックスを返し、モデルはこのインデックスを元のデータの行と照合します。これは、ビュー内の順序が決して変更されないようにすることを意味します。これは可能ではありますが、ビューがデータを表示 (および操作) する方法を制限します。これはまた、モデルをビュー データ (行インデックス) で汚染します。

    public int RowIndexSelected { get; private set; }

    //...//

    private void gridParts_CellEnter(object sender, DataGridViewCellEventArgs e)
    {
        if (SelectedPartChangedEvent != null)
        {
            RowIndexSelected = e.RowIndex;

            SelectedPartChangedEvent();            
        }
    }

3) (2) のバリエーション。プレゼンターとビューの間に配置するアダプター オブジェクトを作成します。行から ID への変換コードをモデルからアダプターに移動します。次に、プレゼンターは dataGridAdapters パーツの変更イベントを処理します。

    public PartSelectDataGridAdapter(IPartSelectView view, PartCollection data)
    {
        _view = view;
        _data = data;

        _view.SelectedPanelChangedEvent += HandleSelectedPartChanged;
    }

    void HandleSelectedPartChanged()
    {
        int id = _data[_view.RowIndexSelected].ID;

        if (SelectedPartChanged != null)
        {
            SelectedPartChanged(id);
        }
    }

現在、テスト可能であるため、3に向けて学習しており、ロジックをビューから除外し、データをモデルとプレゼンターから除外しています。

これにどのように取り組みますか - より良い解決策はありますか?

4

3 に答える 3

2

以前に簡単な解決策を投稿しました。これは質問に対するより詳細な回答です

ビューにを渡したくない理由はありList<Part>ますか?

IDと電圧の列を非表示にするようにグリッドを構成できます。ビューのバインディングソースから選択したオブジェクトを取得するだけです。プレゼンターは、この選択についてビューにクエリを実行するか、ビューがSelectionChanged(Part selected)プレゼンターでを呼び出すことができます。

これは、パッシブビューのパターンに厳密に従っていないことを意味しますが、ビューがモデルについて認識しているため、監視コントローラーです。

これが気に入らない場合は、DataTableですでに暗黙的に行っているビューモデルを導入できます。(これは必ずしも悪いことではありません、ところで。)

この例では、モデルにビューモデルを生成するメソッドがあるため、モデルクラスはビューモデルについて認識しています。この関係を逆にすることをお勧めします。モデルオブジェクトに依存するメソッドをビューモデルに作成します。このようにして、モデルクラスをきれいに保ち、プレゼンテーション層で必要なすべてのUIデータから独立させます。

ビューモデル/監視コントローラーの方法を使用する場合は、単純なクラスを優先してDataTableの概念を削除することを検討してください。

編集:ビューをモデルから完全に無視するための代替手段:

モデルとビューモデルの両方を知っているプレゼンターで、このクラスのインスタンスを作成します。

public class PartViewModel
{
  object PartModel { get; set; }
  string Name { get; set; }
  string Description { get; set; }
}

List<PartViewModel>データソースとしてをDataGridViewに渡します。選択したPartViewModelオブジェクトをプレゼンターに返すことができます(イベントまたはメソッドのいずれかを使用)。プレゼンターは、PartModelプロパティをPartインスタンスにキャストして戻すことができることを知っています。あなたが好んでいると言うように、ビューはモデルについて何も知る必要はありません。ただし、IDを使用した「複雑な」ルックアップを回避して、プレゼンターで単純なオブジェクトIDを使用することはできます。

プレゼンターコールバックあり:

interface IPartListPresenter
{
  // other methods
  void SelectedPartChanged(PartViewModel nowSelected);
}

partBindingSourceがグリッドビューが接続されているバインディングソースであるとすると、partBindingSourceのCurrentChangedイベントを次のように処理できます。

private void partBindingSource_CurrentChanged(object sender, EventArgs e)
{
  _presenter.SelectedPartChanged(partBindingSource.Current as PartViewModel);
}

プレゼンターの場合:

public void SelectedPartChanged(PartViewModel nowSelected)
{
  if(nowSelected == null)
  {
    return;
  }
  part myPart = (Part) nowSelected.Part;
  // dos stuff
}

お役に立てれば。

于 2010-12-08T11:55:36.463 に答える
1

ID はユーザーに表示されず、電圧も表示されないため、モデルは partCode と説明のみを含む DataTable を作成します。

簡単な解決策:データテーブルにID列を作成、データグリッドビューで非表示にします

于 2010-12-08T11:50:54.550 に答える
0

ここで全体のコンセプトを少し誤解していると思います!

モデルではなく、これを処理するのはプレゼンターです。モデルはその唯一の責任にのみ集中する必要があります。そうでない場合は、ビューとモデルを近づけすぎます。

私の提案は、テーブルに非表示の列を保持し、選択した行のイベントをプレゼンターに渡してから、プレゼンターに作業を処理させることです。

これがMVPの正しい使い方になります。

于 2010-12-08T11:52:35.277 に答える