はじめに
Windowsフォームはきれいにコードを書くのが難しい?らしいので、
Model-View-Presenterというパターンで構成要素を分割してみました。
実装
Viewデザイン
画面はこんな感じでラベル2つとボタンを1つ配置。
これがViewになります。
Viewインターフェース
先ほどのフォーム(View)に情報を流し込むためのインターフェースを定義。
ボタンを押したときにメッセージボックスを出したいので、デリゲートも入れます。
こいつがフォーム(View)に実装されることになります。
public interface IMainForm
{
string Title { get; set; }
string Author { get; set; }
Action<string> ShowMessageCommand { get; set; }
}
Presenter
次はPresenter。こいつがViewで表示される情報を準備します。
コンストラクタでViewを受け取り、さっきのインターフェース経由で情報を渡します。
public class MainFormPresenter
{
private IMainForm _view;
public MainFormPresenter(IMainForm view)
{
_view = view;
Initialize();
}
private void Initialize()
{
// HACK: 本当はこのあたりはModelから取得されるはずのデータ
_view.Title = "MvpWinFormsTest!";
_view.Author = "mono";
_view.ShowMessageCommand += (msg) =>
{
MessageBox.Show(msg);
};
}
}
View
Viewのコードビハインド。
IMainFormを実装することで、Presenterからの情報の受取口を付けてやります。
public partial class MainForm : Form, IMainForm
{
public MainForm()
{
InitializeComponent();
}
public string Title
{
get { return label1.Text; }
set { label1.Text = value; }
}
public string Author
{
get { return label2.Text; }
set { label2.Text = value; }
}
public Action<string> ShowMessageCommand { get; set; }
private void button1_Click(object sender, EventArgs e)
{
ShowMessageCommand("button1 Clicked!");
}
}
Presenterインスタンスの生成
フォームを表示する時に、フォームに紐づいたPresenterも作ってやります。
static class Program
{
/// <summary>
/// アプリケーションのメイン エントリ ポイントです。
/// </summary>
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
var f = new MainForm();
var p = new MainFormPresenter(f);
Application.Run(f);
}
}
動作
まとめ
MVPらしき方法で動かすことができました。
雰囲気としては、MVVMのデータバインドがやっていることを自分で組んでいるような感じがしました。
今回以下のような疑問が残りました。
- メッセージ表示をデリゲートでやったけど、ViewからPresenterを参照できるようにして、メソッドを呼び出した方がいいのかな
- 画面遷移・入力ダイアログはどうやって実装しよう
- DataGridViewとかBindingSourceとかDataTableとか使いだしても、うまく組めるのか
- この方法でコードの保守性は上がるのはどんな場面か
色々サンプルを探してみたのですが、ゴチャゴチャした画面は見当たらなかったです。
WinForms対応のMVP用の部品も色々あったのですが、ディスコンのものばかりで試していません。
もうちょっと凝った画面も作ってみようかなと思います。
参考資料
mrts/winforms-mvp: Windows Forms example of the Passive View variant of the Model-View-Presenter pattern
https://github.com/mrts/winforms-mvp