SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

DeveloperZine(デベロッパージン)- エンジニアの意思決定を支える技術情報メディア ProductZine

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

japan.internet.com翻訳記事

Visual WebGUIによるAJAX対応CMS(コンテンツ管理システム)の構築
フレームワークの作成

柔軟なソフトウェアシステムの開発には、強固なフレームワークが不可欠

ワークプレースとモジュールのクラスの使用例

 LoadModuleメソッドでは、ワークプレースのコンテナにモジュールをロードする処理と、適切なイベントを対応付ける処理を行い、ロードする側とされる側のモジュール間での制御の受け渡しを実現します。

public static IWTModule LoadModule(IWTWorkplace hostPanel, 
  IWTModule module, IWTModule parentModule, bool loadVisible){
  Control control = module as Control;
  if (control == null)
    module = null;
  else {
    Control hostBody = hostPanel.BodyPanel;
    // assign a unique name to the module we add, 
    // based on existing controls already loaded
    int currentControlCnt = hostBody.Controls.Count + 1;
    control.Name = hostBody.Name + "_ctrl" + currentControlCnt;
    control.Location = new System.Drawing.Point(1, 1);
    control.Dock = DockStyle.Fill;
    hostBody.Controls.Add(control);
    // if we don't have to show the control right now 
    // then just don't do anything
    if (!loadVisible)
      control.Visible = false;
    else 
      ShowModule(hostPanel, module);
    // set reference to caller module
    module.CallerModule = parentModule;
    // finally, set reference to workplace panel
    module.HostWorkplace = hostPanel;
    // bind close event to the controller, so it can get notified 
    // when a module needs to close, and perform required actions
    module.Close +=new WTCancelGenericEventHandler(Module_Close);
  }
  return module;
}

 Closeイベントのハンドラでは、モジュールをワークプレースから削除します。さらにオプションで、呼び出し元のモジュールに制御を戻し、終了するモジュールからの引数を渡します。

static void Module_Close(object sender, WTCancelGenericEventArgs e) {
  IWTModule module = sender as IWTModule;
  if (module != null)
  {
    // ret reference to caller module and the workplace
    IWTModule parentModule = module.CallerModule;
    IWTWorkplace workplace = module.HostWorkplace;
    // and removes the module from workplace to unload it
    workplace.RemoveModule(module);
    if (parentModule != null)
    {
      // if I have reference to parent module
      // check if the module was not canceled, and if so
      // call Refresh method of the caller module passing 
      // it received arguments, so it can update itself
      if (!e.Cancel)
        parentModule.Refresh(e);
      // get reference to workplace the parent is loaded into
      workplace = parentModule.HostWorkplace
      // and activate the parent
      workplace.ShowModule(parentModule);
    }
  }
}

 上のコードで要注目なのが、WTCancelGenericEventHandlerとWTCancelGenericEventArgsの2つです。WTCancelGenericEventHandlerは、WTCancelGenericEventArgsと組み合わせて使うデリゲートです。キャンセル可能なジェネリックイベントベースの仕組みを実現します。この仕組みを使うことにより、モジュール間であらゆるデータをEventArgsとして受け渡すことができます。これについては後で解説します。

 インターフェースとWTWorkplaceControllerの準備ができたら、次は実際のコンポーネントの作成です。ワークプレースもモジュールもUserControlを継承し、さらにワークプレースはIWTWorkplaceを、モジュールはIWTModuleを、それぞれ実装します。WTWorkplaceコンポーネントのコードは次のとおりです。

public partial class WTWorkplace : UserControl, IWTWorkplace {
   protected Control m_container;
   public WTWorkplace(){
      InitializeComponent();
      m_container = (Control)this;
   }
   public string Caption {
      get { return this.Text; }
      set { 
         m_container.Text = value;
      }
   }
   public virtual Control BodyPanel {
      get {
         if (m_container == null)
            m_container = this;
         return m_container; 
      }
   }
   public IWTModule LoadModule(IWTModule module, 
      IWTModule parentModule) {
      return WTWorkplaceController.LoadModule(
         this, module, parentModule, true);
   }
   public IWTModule LoadModule(IWTModule module, 
      IWTModule parentModule, bool loadVisible) {
      return WTWorkplaceController.LoadModule(
         this, module, parentModule, loadVisible); 
   }
   public void ShowModule(IWTModule module) {
      WTWorkplaceController.ShowModule(this, module);
   }
   public void RemoveModule(IWTModule module) {
      WTWorkplaceController.RemoveModule(this, module);
   }
   public void HideAllModules() {
      WTWorkplaceController.HideAllModules(this);
   }
   public bool CheckModuleExists(IWTModule module) {
      return WTWorkplaceController.CheckModuleExists(this, module);
   }
}

 コードは簡潔です。いずれのメソッドも、WTWorkplaceControllerクラスで定義された同様のメソッドを呼び出すだけのラッパーです。

 本稿のダウンロードサンプルにも、WTHeaderedWorkplaceクラスのコードが含まれています。

※筆者注

 Visual WebGUIは開発のペースが速く、現在のバージョンは6.3.8aです。本稿のダウンロードサンプルもこのバージョンで動作を確認しています。ダウンロードしたサンプルソリューションをビルドして実行するためには、Visual WebGUIのProfessional版をダウンロードしてインストールし、デモ/試用として登録する必要があります。無料のExpress版でもテストは可能ですが、その場合はコードを構成し直すことが必要です。Visual Studio ExpressではWebプロジェクトを利用できないため、コードをWebサイトとして構成する必要があるからです。

 WTHeaderedWorkplaceクラスは、HeaderedPanelとして実装したワークプレースコンポーネントです。実装の中身は次のように簡単なものです。

  • WTWorkplaceを継承した新しいコンポーネントをWTHeaderedWorkplaceという名前で作成する
  • そのコンポーネントにHeaderedPanelを追加し、コンストラクタに次のコードを使用する
public partial class WTHeaderedWorkplace : WTWorkplace {
    public WTHeaderedWorkplace() {
InitializeComponent();
        headeredPanel.Dock = Gizmox.WebGUI.Forms.DockStyle.Fill;
        m_container = headeredPanel;
    }
}

 WTModuleは、UserControlを継承し、IWTModuleを実装しています。こちらのコードも、各メンバの中身は極めて単純です。ワークプレースモジュールと親モジュールへの参照を保持する2つのprivateフィールドのgetter/setterにすぎません。

    // ...
    private IWTWorkplace m_hostPanel;
    private IWTModule m_callerModule;
    public IWTWorkplace HostWorkplace {
        get { return m_hostPanel; }
        set { m_hostPanel = value; }
    }
    public IWTModule CallerModule {
        get { return m_callerModule; }
        set { m_callerModule = value; }
    }

 Refreshメソッドは仮想メソッドとして実装しており、アプリケーションのモジュールでオーバーライドする必要があります。呼び出された側のモジュールの終了時に保存すべきデータがある場合に、呼び出し側のモジュールを更新する処理を行います。

public virtual void Refresh(WTCancelGenericEventArgs e){ }

 WTModuleには、重要なプロテクトメソッドであるCloseModuleもあります。同じ名前のメソッドが3種類あり、それぞれパラメータが異なります。

// CloseModule should be called when the module needs to be closed
// it fires Close event, which is intercepted by WTWorkplaceController    
protected void CloseModule() {
   CloseModule(false);
}
protected void CloseModule(bool cancel) {
   CloseModule(new WTCancelGenericEventArgs(cancel));
}
protected void CloseModule(WTCancelGenericEventArgs e){
   if (Close != null)
      Close(this, e);
}   

 モジュールが閉じるときには、この3つのいずれか1つを呼び出す必要があります。1つ目の引数なしのメソッドを呼び出すのは、モジュールが不要となって閉じる場合です。2つ目のCloseModule(bool cancel)を呼び出すのは、次のいずれかの場合です。

  • キャンセルボタンのクリックによりモジュールを閉じる場合。このときはパラメータにtrueを渡す
  • モジュールを閉じるが、保存すべきデータはない場合。このときはパラメータにfalseを渡す
  • モジュールを閉じ、データを保存するが、呼び出し側のモジュールにはデータを渡す必要がない場合

 3つ目のメソッドを呼び出すのは、モジュールを閉じるときに呼び出し元のモジュールにデータを渡す必要がある場合です。この処理の例は、本稿のサンプルアプリケーションのModuleNameモジュールとDashboardモジュールにあります。

// in called module, in the event handler for Save button
private void buttonSave_Click(object sender, EventArgs e) {
    WTCancelGenericEventArgs evt = new WTCancelGenericEventArgs();
    evt.AddEventData("name", textName.Text);
    CloseModule(evt);
}
// . . .
// in caller module, the code for Refresh method
public override void Refresh(WTCancelGenericEventArgs e){
    if (e.Cancel)
        statusBar1.Text = "Name was canceled";
    else {
        if (e.ExistsEventData("name"))
            statusBar1.Text = 
                string.Format("Welcome, {0}", 
                    e["name"].ToString());
    }
}

 必要なコードは以上です。次は、スタートアップフォームの登録と設定です。

次のページ
スタートアップフォームの登録と設定

この記事は参考になりましたか?

japan.internet.com翻訳記事連載記事一覧

もっと読む

この記事の著者

japan.internet.com(ジャパンインターネットコム)

japan.internet.com は、1999年9月にオープンした、日本初のネットビジネス専門ニュースサイト。月間2億以上のページビューを誇る米国 Jupitermedia Corporation (Nasdaq: JUPM) のニュースサイト internet.comEarthWeb.com からの最新記事を日本語に翻訳して掲載するとともに、日本独自のネットビジネス関連記事やレポートを配信。

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

Bogdan Zamfir(Bogdan Zamfir)

 コンピュータ科学で修士号を取得。1993年から独立系コンサルタント兼ソフトウェア開発者として活躍する。Webアプリケーションとデスクトップアプリケーションの両方を手がける。使用言語とプラットフォームは、C#、VB.NET、Visual FoxPro、Microsoft Access、Visual ...

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

CodeZine(コードジン)
https://codezine.jp/article/detail/4395 2009/09/24 14:00

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー