高見知英のかいはつにっし(β)

高見知英のアプリケーション開発日誌 のほか、地域活動などの活動報告ブログ。

設定ダイアログを作ろう(C#)

 設定ダイアログというと、一番簡単に使えるのはタブを使ったダイアログですが、.NETフレームワークのタブコントロールは、WindowsXPのビジュアルスタイルに(完全には)対応していません。
まあ、C言語のダイアログあたりだと割と当たり前のようなので、その辺は仕方ないと諦めればいいのでしょうが、それでは何となく不満です。そこで、WindowsXPでも不自然のないダイアログを作ってみたいと思います。

 さて、WindowsXPでも不自然のないダイアログとなるとタブコントロールは使えません。ですから最近OperaFireFoxなどの設定ダイアログでよく見かける、リストボックスタイプの設定ダイアログになります。
そうなると問題なのは、どうやって設定項目を作るか ですね。Panelを順次表示するのも良いですが、(IDE上での)編集が面倒です、Delphiなどだと、タブページに"TabVisible"プロパティがあるので、タブコントロールで設定項目を作り、TabVisibleをいじれば解決するのですが…。
 そこで出てくるのが、UserControlです。これは、Delphiで言うのならばフレームのように、いくつかのコントロールを乗っけて、あたかも一つのコントロールのように扱えるものです。これを作成して、フォームのサイズに合わせ、リストから呼び出せば完成です。

設定パネル共通のインターフェース

 まずは、下準備として設定用パネル(UserControl)すべてに共通の関数を定義します。ベース用のコントロールを継承して作っても良いですが、それをするとSharpDevelopではデザインが出来なくなってしまいますので、インターフェースです。
とりあえず、わたしはおんぷ村のうらにある、MemXMLFile(配布されてるバージョンにはバグがあります、ごめんなさい、今度修正版アップします)を使いますから、

  public interface ISaveControl
  {
    void LoadControl(Chie.Ini.MemXMLFile xml);
    void SaveControl(Chie.Ini.MemXMLFile xml);
  }

 とします。

ユーザーコントロールの作成

 次に、ユーザーコントロールを作成します。複数のページを作るときは、Sizeを合わせて置いてください。DockやAnchorを駆使するのも悪くないかも知れません(未確認)。
このユーザーコントロールで必要なのは、ISaveControlを実装することと、ToStringをオーバーライドすることだけ。
ToStringについては他の方法でも良いですが、リストボックスに設定内容(キャプション)を表示するために、ToStringを使います、これだと、リストボックスにコントロールを追加するだけで文字列が表示されます。

コンフィグダイアログ(ベース)の作成

 最後にメインのダイアログを作成します。必要なコントロールは

  • リストボックス
  • パネル(ユーザーコントロール格納用)
  • OKボタン、キャンセルボタン

だけ。パネルは不可欠ではありませんが、ユーザーコントロールの座標を簡単に決定できるので置いておくと良いでしょう。
 そして、フォームのコンストラクタで、リストボックスにユーザーコントロールを追加します。

  configList.Items.Add(new WindowsSetting());
  configList.Items.Add(new ExtSetting());
  configList.Items.Add(new ToolSetting());
  configList.SelectedIndex = 0;

で、フォームのロード(別にこのすぐ下でも良いですが)時に、全アイテムのISaveControl.LoadControlを呼び出します。

  Chie.Ini.MemXMLFile xml = new Chie.Ini.MemXMLFile(Constant.SettingFile);
  foreach(UserControl control in configList.Items)
  {
    ISaveControl save = (ISaveControl)control;
    save.LoadControl(xml);
  }

OKボタンが押されたときには、ISaveControl.SaveControl やり方は上と同じです。

  Chie.Ini.MemXMLFile xml = new Chie.Ini.MemXMLFile(Constant.SettingFile);
  foreach(UserControl control in configList.Items)
  {
    ISaveControl save = (ISaveControl)control;
    save.SaveControl(xml);
  }
  xml.UpdateFile();

 最後の仕上げに、リストボックスのアイテム選択に応答するために、リストボックスのSelectedIndexChangedイベントで

  configPanel.Controls.Clear();
  UserControl control = ((UserControl)configList.SelectedItem);
  configPanel.Controls.Add(control);
  control.Location    = new Point(0, 0);

 とします。ここで最初に設置したPanelの出番です。Panelを用意することで、座標をnew Point(0, 0);とするだけで設定できます。Dock.Fillでも良いですね。


 と、以上で完成です。呼び出す側は普通にShowModalで呼び出すだけです。近いうちにおんぷ村のうらにでもおきたいですね。