12
13

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

WindowsフォームをMVPっぽくしてみる

Posted at

はじめに

Windowsフォームはきれいにコードを書くのが難しい?らしいので、
Model-View-Presenterというパターンで構成要素を分割してみました。

実装

Viewデザイン

画面はこんな感じでラベル2つとボタンを1つ配置。
これがViewになります。
image.png

Viewインターフェース

先ほどのフォーム(View)に情報を流し込むためのインターフェースを定義。
ボタンを押したときにメッセージボックスを出したいので、デリゲートも入れます。
こいつがフォーム(View)に実装されることになります。

IMainForm.cs
public interface IMainForm
{
    string Title { get; set; }
    string Author { get; set; }
    Action<string> ShowMessageCommand { get; set; }
}

Presenter

次はPresenter。こいつがViewで表示される情報を準備します。
コンストラクタでViewを受け取り、さっきのインターフェース経由で情報を渡します。

MainFormPresenter.cs
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からの情報の受取口を付けてやります。

MainForm.cs
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も作ってやります。

Program.cs
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);
    }
}

動作

ボタンも含めうまく動いているようです。
image.png

まとめ

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

12
13
4

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
12
13

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?