7

MVP で実装された WinForms アプリケーションがあります。私のフォームには があり、そのプロパティをモデルのプロパティにTextBoxデータバインドしたいと考えています。Textビューでモデルを参照したくありません。

Google で検索したところ、Model と View を結合してデータバインディングするのは良くない考えであることがわかりました。ModelViewおよびの私のサンプル初期化はPresenter次のとおりです。

class View : Form, IView
{
    public View()
    {
        InitializeComponent();
        new Presenter(this);
    }
}

class Presenter
{
    public Presenter(IView) : this.Presenter(this, new Model())
    {
    }

    public Presenter(IView view)
    {
    }
}

class Model : IModel
{
    public Model()
    {
    }

}

Model現在、 、 、のそれぞれに 3 つのプロジェクトがViewありPresenterます。ビューには への参照がPresenterあり、へのPresenter参照がありModelます。Viewプロパティへのコントロールへのデータバインディングを形成する方法を教えてもらえますModelか?

編集

私はグリッドで物事を行うことを知っています。Datasource次のように、グリッドのプロパティをListプレゼンターの (または類似のもの) に割り当てることができます。

_view.DataSource = _model.ListOfEmployees;

ListOfEmployeesこれは、モデルの変更時に UI の値を反映します。しかし、プロパティTextBoxを公開する はどうでしょうか? TextMVP アーキテクチャでそれをバインドするにはどうすればよいですか?

4

3 に答える 3

10

My recommendation is to encapsulate the View and Model in the Presenter. This means a specialized Presenter (in most cases) for a given View. In my opinion, this works out well since most Models will be different anyway.

class Presenter {
    readonly IView view;
    readonly IModel model;

    public Presenter() {
        // if view needs ref. to presenter, pass into view ctor
        view = new View(this);
        model = new Model();
    }

    // alternatively - with the model injected - my preference
    public Presenter(IModel Model) {
        // if view needs ref. to presenter, pass into view ctor
        view = new View(this);
        model = Model;
    }
}

In your IView, expose a control or control's data source property:

interface IView {
    object GridDataSource { get; set; }
}

Add to your Presenter some method:

void SetGridDatasource() {
    view.GridDatasource = model.SomeBindableData;
}

View implementation:

public object GridDatasource {
    get { return myGridView.DataSource; }
    set { myGridView.DataSource = value; }
}

Note:
Code snippets are untested and recommended as a starting point.

Update to comments:
INotifyPropertyChanged is a very valuable mechanism for updating properties between IView and IModel.

Most controls do have some sort of binding capability. I would recommend using those DataBinding methods whenever possible. Simply expose those properties through IView and let the Presenter set those bindings to the IModel properties.

于 2013-02-01T20:10:13.720 に答える
6

説明:

テキストボックスをモデルの基礎となるプロパティにデータバインドする場合:

最初: 他の多くの状態と同様に、プロパティを含むものはすべて INotifyPropertyChanged インターフェイスを実装する必要があります。これにより、オブジェクト プロパティが変更されたときに、必要なイベントが発生してビューに変更が通知されます。この点で、ビューモデルをモデルのプロパティとして使用して、ビューをデータバインドしたい特定のプロパティをカプセル化します。

2 番目: IView には、View が実装する必要がある viewmodel プロパティが含まれます。

3 番目: View は、viewmodel オブジェクトに set アクセサーのみを使用して IView プロパティを実装し、各テキスト ボックスを dto プロパティにデータバインドします。以下の例で、ビューの読み込み後にテキストボックスを手動で設定することは決してないことに注意してください。基になるモデルのビューモデル プロパティが変更されると、textbox.text の値が更新されるようになりました。これは両方の方法で機能します (2 方向のデータバインディング)。ユーザー入力でテキストボックスを編集すると、基になるモデルの dto プロパティ値が変更されます。

4 番目: プレゼンターは、ビューの読み込み時に IView のプロパティをモデルのプロパティに 1 回だけ設定します。

例: これは非常に単純化された大まかな例であり、OP が使用しているようなモデルの抽象化はありませんが、Winforms MVP でのテキスト ボックス データ バインディングの良い出発点になるはずです。本番アプリで変更するもう 1 つのことは、モデルをステートレスにし、ビューモデル (人物) をプレゼンターに移動することです。

//VIEWMODEL
public class Person : INotifyPropertyChanged
{
    string _firstName;
    string _lastName;
    public string FirstName
    {
        get { return _firstName; }
        set
        {
            if(value != _firstName)
            {
                _firstName = value;
                NotifyPropertyChanged("FirstName");
            }
        }
    }
    public string LastName
    {
        get { return _lastName; }
        set
        {
            if (value != _lastName)
            {
                _lastName = value;
                NotifyPropertyChanged("LastName");
            }
        }
    }
    public event PropertyChangedEventHandler PropertyChanged;

    private void NotifyPropertyChanged(String info)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(info));
        }
    }

}

//MODEL
class Model
{
    Person _person;
    public Person Person { get { return _person; } }

    public Model()
    { 
        //Set default value
        _person = new Person(){ FirstName = "Test", LastName = "Subject" };
    }

    public void ChangePerson()
    {
        //When presenter calls this method, it will change the underlying source field and will reflect the changes in the View.
        _person.FirstName = "Homer";
        _person.LastName = "Simpson";
    }
}

//PRESENTER
class Presenter
{
    readonly View _view;
    readonly Model _model;
    public Presenter(View view)
    {
        _view = view;
        _model = new Model();

        _view.OnViewLoad += Load;
        _view.OnChangePerson += ChangePerson;
    }

    private void Load()
    {
        _view.Person = _model.Person;
    }

    private void ChangePerson()
    {
        _model.ChangePerson();
    }
}

//IVIEW
interface IView
{
   Person person { set; }

   event Action OnViewLoad;
   event Action OnChangePerson;
}

//VIEW
public partial class View : IView
{
     public View()
     {
         Presenter presenter = new Presenter(this); 
         this.Load += (s, e) => OnViewLoad(); //Shorthand event delegate
         this.btnChange.Click += (s, e) => OnChangePerson(); //Shorthand event delegate
     }

     public event Action OnViewLoad;
     public event Action OnChangePerson;

     public Person person
     {   //This is how you set textbox two-way databinding
         set
         {
               //Databinding syntax: property of control, source, source property, enable formatting, when to update datasource, null value
               txtFirstName.DataBindings.Add(new Binding("Text", value, "FirstName", true, DataSourceUpdateMode.OnPropertyChanged, string.Empty));
               txtLastName.DataBindings.Add(new Binding("Text", value, "LastName", true, DataSourceUpdateMode.OnPropertyChanged, string.Empty)); 
         }
     }

}
于 2016-07-31T18:20:09.023 に答える