連載:Windowsフォーム開発入門【Visual Studio 2010対応】

独自Windowsフォーム・クラスの活用

初音 玲
2011/04/05
Page1 Page2

Windowsフォーム・クラス・ライブラリの継承

 複数の.EXEファイルから構成されているようなシステムで、Windowsフォームを継承して別のWindowsフォームを定義する場合には、継承元のWindowsフォームをクラス・ライブラリとして定義し、そのクラス・ライブラリを使って継承する方法をお勧めする。

 では、順を追ってその方法を説明していこう。

Windowsフォーム・アプリケーションのプロジェクトの作成

 通常の手順でWindowsフォーム・アプリケーションのプロジェクトを作成する。次の画面は、「WinInherits」という名前でWindowsフォーム・アプリケーションの新規プロジェクトを作成した直後の[ソリューション エクスプローラー]の表示例である。

図6 Windowsフォーム・アプリケーションのプロジェクトの作成

Windowsフォーム・クラス・ライブラリのプロジェクトの追加

 次に、ソリューションにWindowsフォーム・クラス・ライブラリのプロジェクトを追加する。この際、[新しいプロジェクトの追加]ダイアログでは「Windowsフォーム アプリケーション」テンプレートを指定する(図7参照)。

図7 新しいWindowsフォーム・アプリケーションのプロジェクトの追加

 もちろん、このままではWindowsフォーム・クラス・ライブラリとして使用できないので、ソリューションに追加した後で、プロジェクトのプロパティの[アプリケーションの種類]ドロップダウンの指定を「クラス ライブラリ」に変更する(図8参照)。

図8 アプリケーションの種類の変更

Windowsフォーム・クラスの定義

図9 クラス・ライブラリのWindowsフォーム定義

 図9のようにソリューションにWindowsフォーム・アプリケーションのプロジェクトとクラス・ライブラリのプロジェクトがそろったら、クラス・ライブラリのプロジェクト(図では「WinClassLibrary」)の中にWindowsフォームのクラスを追加して、それら(図9では「Login_Form.vb」と「Main_Form.vb」)に共通的なデザインを定義する。共通的なデザインといっても何も特別な手順は不要で、通常のWindowsフォームと同じようにコントロールを貼り付け、コントロールに対するイベント・プロシージャを定義すればよい。

 Windowsフォーム・クラス・ライブラリ特有の工夫としては、次の2点を考慮するとよいだろう。

(1) 継承先との間の情報共有のためのプロパティを用意
(2) 継承先で書き換えが生じそうなコードについては「オーバーライド可能」で定義

 今回のサンプルでは、プロパティとしてユーザーIDとパスワードを用意し、データの取得と更新部分をオーバーライド可能にしている。

Public Class Main_Form
  Public Property UserID As String
  Public Property Password As String
  Public Property IsUpdate As Boolean
  Public Property Ds As DataSet

  Private Sub Form1_Shown(sender As Object,
              e As System.EventArgs) _
            Handles Me.Shown
    If Not DesignMode Then
      Using _form As New Login_Form
        If _form.ShowDialog(Me) Then
          Me.UserID = _form.UserID
          Me.Password = _form.Password
        Else
          Me.Close()
        End If
      End Using
    End If
  End Sub

  Private Sub Form1_FormClosing(sender As Object,
                  e As FormClosingEventArgs) _
                Handles Me.FormClosing
    If IsUpdate Then
      Dim result As DialogResult =
        MessageBox.Show("データを保存してから終了します。",
                My.Application.Info.Title,
                MessageBoxButtons.YesNoCancel)
      Select Case result
        Case DialogResult.Yes
          e.Cancel = Not SetRecords()
        Case DialogResult.No
        Case Else
          e.Cancel = True
      End Select
    End If
  End Sub

  Public Overridable Function GetRecords() As DataSet
    Throw New NotImplementedException
  End Function

  Public Overridable Function SetRecords() As Boolean
    Throw New NotImplementedException
  End Function

End Class
using System;
using System.Data;
using System.Windows.Forms;

namespace WinClassLibraryCs
{
  public partial class Main_Form : Form
  {

    public String UserID { get; set; }
    public String Password { get; set; }
    public Boolean IsUpdate { get; set; }
    public DataSet Ds { get; set; }

    public Main_Form()
    {
      InitializeComponent();
    }

    private void Main_Form_Shown(object sender, EventArgs e)
    {
      if (!DesignMode)
      {
        using (Login_Form _form = new Login_Form())
        {
          if (_form.ShowDialog(this) == DialogResult.OK)
          {
            this.UserID = _form.UserID;
            this.Password = _form.Password;
          }
          else
          {
            this.Close();
          }
        }
      }
    }

    private void Main_Form_FormClosing(object sender, FormClosingEventArgs e)
    {
      if (IsUpdate)
      {
        DialogResult result =
          MessageBox.Show("データを保存してから終了します。",
          "",
          MessageBoxButtons.YesNoCancel);
        switch (result)
        {
          case DialogResult.Yes:
            e.Cancel = !SetRecords();
            break;
          case DialogResult.No:
            break;
          default:
            e.Cancel = true;
            break;
        }
      }
    }

    public virtual DataSet GetRecords()
    {
      throw new NotImplementedException();
    }

    public virtual bool SetRecords()
    {
      throw new NotImplementedException();
    }
  }
}
リスト3 Windowsフォーム・クラス・ライブラリの例(上:VB、下:C#)

 Shownイベントのイベント・プロシージャで「Not DesignMode」(VBの場合。C#は「! DesignMode」)のときのみログイン画面を表示するようにしている点に注目してほしい。

 この判定が必要なのは、IDEがソリューションを読み込んだときにクラス・ライブラリのFormクラスのLoadedイベントやShownイベントが発生し、IDEで読み込むたびにログイン画面が自動的に表示されてしまうからだ。

Windowsフォーム・クラスの継承

 Windowsフォーム・アプリケーションのプロジェクトで、先ほどのクラス・ライブラリを参照設定したら、[新しい項目の追加]ダイアログで「継承されたフォーム」テンプレートを選択して、その後に表示される[継承ピッカー]ダイアログで[参照]ボタンから、(継承元となる)Windowsフォーム(本稿の例では「Main_Form」)を指定する。

 Windowsフォーム・アプリケーション側では、ここまでまったくコードを記述していない。この状態で、Windowsフォーム・アプリケーションのプロジェクトをスタートアップ・プロジェクトに指定して実行すれば、Windowsフォームが表示されてから、自動的にログイン画面が表示される。図10はその例。

図10 サンプルの実行結果

 このようにログイン画面まで基本クラスで定義することで、複数の.EXEファイルに分割して業務システムを構築したときでも、各.EXEファイルのメイン画面に同じ操作性のログイン画面の実装が簡単に行える。もちろん、メイン画面以外ではログイン画面は不要なのでメイン画面以外のひな型フォームも別の基本クラスとしてクラス・ライブラリに定義しておくとよいだろう。

まとめ

 業務アプリケーションを構築するときにUIデザインの統一は非常に重要だ。

 .NET以前の手法であれば、共通デザインを行ったWindowsフォームを「ひな型フォーム」として最初に作成し、後はそのWindowsフォームをコピーしてから各機能に応じた画面を作成する手法が主流であった。しかしこの方法では、後から「ひな型フォーム」に変更が生じた場合に、コピーして作成したWindowsフォームへその変更を反映するのに非常に手間がかかってしまう。そのため「ひな型フォーム」の作成には十分な検討が必要になり、「後戻りして直す」という作業自体を前提としないウォータフォール的な手法が必要になる。

 しかし、「ひな型フォームのクラス・ライブラリ」でデザインの統一を実現すれば、後から共通部分に変更がかかってもクラス・ライブラリ側の変更のみで、各Windowsフォームへはその変更が自動的に継承されることになる。このように後からの変更が容易であれば、徐々に作りながら「ひな型フォーム」の仕様を詰めていきやすい。ぜひ、自分たちの「ひな型フォームのクラス・ライブラリ」を作成して作業の効率化を図ってみてほしい。end of article


 INDEX
  [連載]Windowsフォーム開発入門【Visual Studio 2010対応】
  独自Windowsフォーム・クラスの活用
    1.Windowsフォーム・クラスの継承
  2.Windowsフォーム・クラス・ライブラリの継承

インデックス・ページヘ  「Windowsフォーム開発入門」


Insider.NET フォーラム 新着記事
  • 第2回 簡潔なコーディングのために (2017/7/26)
     ラムダ式で記述できるメンバの増加、throw式、out変数、タプルなど、C# 7には以前よりもコードを簡潔に記述できるような機能が導入されている
  • 第1回 Visual Studio Codeデバッグの基礎知識 (2017/7/21)
     Node.jsプログラムをデバッグしながら、Visual Studio Codeに統合されているデバッグ機能の基本の「キ」をマスターしよう
  • 第1回 明瞭なコーディングのために (2017/7/19)
     C# 7で追加された新機能の中から、「数値リテラル構文の改善」と「ローカル関数」を紹介する。これらは分かりやすいコードを記述するのに使える
  • Presentation Translator (2017/7/18)
     Presentation TranslatorはPowerPoint用のアドイン。プレゼンテーション時の字幕の付加や、多言語での質疑応答、スライドの翻訳を行える
@ITメールマガジン 新着情報やスタッフのコラムがメールで届きます(無料)
- PR -

注目のテーマ

業務アプリInsider 記事ランキング

本日 月間
ソリューションFLASH