連載:Microsoft AJAX Library&JavaScriptプログラミング

第4回 MS AJAX LibでAJAX対応コントロールを開発しよう(後編)

山田 祥寛(http://www.wings.msn.to/
2008/02/08
Page1 Page2 Page3 Page4

[4]Behaviorオブジェクトを編集する

 続いて、Behaviorオブジェクトを編集する。やや長いコードとなるが、注目すべき点は限定されている。全体的な構造については、ここまでの解説を踏まえながら読み解いていただきたい。

// MyAjaxLib名前空間を宣言
Type.registerNamespace("MyAjaxLib");

// MyAjaxLib.DialogButtonExternalBehaviorクラスの
// コンストラクタを定義
MyAjaxLib.DialogButtonExternalBehavior = function(element) {

  // 基底クラスのコンストラクタをコール
  MyAjaxLib.DialogButtonExternalBehavior.initializeBase(
    this, [element]);

  // Messageプロパティの値を格納するためのプライベート変数を宣言
  this._Message = '';

  // クラス内部で使用するそのほかのプライベート変数を定義
  this._displayed = false; // メッセージボックスが表示状態か
  this._dialogElement = null; // メッセージボックスを表す<div>要素
  this._popup = null; // メッセージボックスをポップアップするBehaviorオブジェクト
}

// MyAjaxLib.DialogButtonExternalBehaviorクラスのメンバを宣言
MyAjaxLib.DialogButtonExternalBehavior.prototype = {

  // コンポーネントを初期化するための
  // initializeメソッドをオーバーライド
  initialize : function() {

    // 基底クラスのinitializeメソッドをコール
    MyAjaxLib.DialogButtonExternalBehavior.callBaseMethod(
      this, 'initialize');

    // ターゲット要素にclickイベント・ハンドラ(_onClick)を適用
    $addHandler(
      this.get_element(),
      'click',
      Function.createDelegate(this, this._onClick)
    );
  },

  // Messageプロパティにアクセスするための
  // アクセサ・メソッドを定義
  get_Message : function() {
    return this._Message;
  },

  set_Message : function(value) {
    if (this._Message !== value) {
      this._Message = value;
      this.raisePropertyChanged('Message');
    }
  },

  // Closedイベントを追加/削除するための
  // addXxxxx/removeXxxxxメソッドを定義
  add_Closed : function(handler) {
    this.get_events().addHandler('Closed', handler);
  },

  remove_Closed : function(handler) {
    this.get_events().removeHandler('Closed', handler);
  },

  // ターゲット要素がクリックされたときの実処理を定義
  _onClick : function(e) {

    // メッセージボックスが非表示状態の場合、
    // メッセージボックスのポップアップを実行
    if (!this._displayed) {

      // メッセージボックスを表す<div>要素を生成
      this._dialogElement =
        CommonToolkitScripts.createElementFromTemplate(
          {
            nodeName : "div",
            properties :
              {
                innerHTML : this._Message
              },
            cssClasses : ["dialog"]
          },
          this.get_element().parentNode
        );


      // ポップアップのためのBehaviorオブジェクトを生成
      this._popup = $create(
        AjaxControlToolkit.PopupBehavior,
        {
          parentElement : this.get_element(),
          positioningMode :
          AjaxControlToolkit.PositioningMode.BottomRight
        },
        null,
        null,
        this._dialogElement
      );

      // メッセージボックスをポップアップ
      this._popup.show();

      // メッセージボックスの表示フラグをtrue(表示中)に変更
      this._displayed = true;
    } else {
      // メッセージボックスを非表示に
      this._popup.hide();

      // Closedイベント・ハンドラを取得し、
      // 存在する場合にのみハンドラを呼び出し
      var h = this.get_events().getHandler('Closed');
      if (h) {
        h(this, Sys.EventArgs.Empty);
      }
      // メッセージボックスの表示フラグをfalse(非表示)に変更
      this._displayed = false;
    }
    return false;
  }
};

// AjaxControlToolkit.BehaviorBaseクラスを継承する
// MyAjaxLib.DialogButtonExternalクラスを登録
MyAjaxLib.DialogButtonExternalBehavior.registerClass(
  'MyAjaxLib.DialogButtonExternalBehavior',
  AjaxControlToolkit.BehaviorBase);
リスト5 DialogButtonExternalコントロールのクライアント側の挙動を定義するBehaviorオブジェクト(DialogButtonExternalBehavior.js)

 コードの全体的な流れはリスト内のコメントを参照いただくとして、ここで注目していただきたいのは以下の2点である。

新規の要素をシンプルなコードで生成する

 Behaviorオブジェクトを記述するうえでは、動的にDOM要素を生成したいという局面は少なからず発生する。もちろん、これを標準的なDOM APIで記述しても構わないわけであるが、要素に付随するプロパティやイベント・ハンドラが複数になる場合、1つの要素を定義するにもコードが冗長になってしまうのはうれしくない。そもそも書き方によっては、1つの要素定義がコードのあちこちに散在してしまう可能性もあり、コードの可読性を損なう一因ともなるだろう。

 そこで登場するのが、CommonToolkitScriptsクラスが提供するcreateElementFromTemplateメソッドなのだ。このメソッドは、その名前のとおり、生成する要素の定義内容をテンプレートで記述するためのメソッドだ。このメソッドを利用することで、プロパティ定義からイベント・ハンドラの定義までを1カ所に、かつ、ハッシュ形式でコンパクトに記述することが可能になる。

 createElementFromTemplateメソッドの一般的な構文は、以下のとおりだ。また、併せてControl Toolkit内のCommon.js(CommonToolkitScriptsクラスを定義したソース・ファイル)に示されている例文も引用しておく(ただしコード内のコメントは筆者によるもの)。

createElementFromTemplate(
  テンプレート(ハッシュ形式),
  親要素
)
CommonToolkitScriptsクラスのcreateElementFromTemplateメソッドの構文

var elt = $common.createElementFromTemplate({ *
  nodeName : "div", // ノード名
  properties : { // プロパティ値の設定
    style : {
      height : "100px",
      width : "100px",
      backgroundColor : "white"
    }, // スタイル(プロパティ名はJavaScript形式)
    expandAttribute : "foo" // そのほかのプロパティ
  },
  events : { // イベント・ハンドラの定義
    click : function() { alert("foo"); },
    mouseover : function() { elt.backgroundColor = "silver"; },
    mouseout : function() { elt.backgroundColor = "white"; }
  },
  cssClasses : [ "class0", "class1" ], // 適用するCSSクラス(配列)
  visible : true, // 可視状態
  opacity : .5 // 透明度
},
someParent // 親要素の設定
);
リスト6 createElementFromTemplateメソッドの記述例
Control Toolkit内のCommon.js(CommonToolkitScriptsクラスを定義したソース・ファイル)に示されている例文。
* $commonは、CommonToolkitScriptsクラスでのエイリアスである。

 以上を踏まえて、リスト5の の部分を読み解いてみると、このコードによって最終的には、以下のような<div>要素が生成されることになる。

<div class="dialog">Messageプロパティの内容</div>

[参考]CommonToolkitScriptsクラス

 CommonToolkitScriptsクラスは、Behaviorオブジェクトの開発に利用できるばかりではない。Webフォームから直接利用することも可能である。CommonToolkitScriptsクラス(正確にはCommonToolkitScriptsクラスを含む、AjaxControlToolkit.dll内のCommon.js)をインポートするには、[ScriptReferenceコレクションエディタ]ダイアログにてScriptManager.Scriptsプロパティにあらかじめ以下の表4のような情報を登録しておけばよい。


図6 [ScriptReferenceコレクションエディタ]ダイアログ

プロパティ 概要 設定値
Assembly スクリプトを含んでいるアセンブリ AjaxControlToolkit
Name アセンブリ内のスクリプト名(パス) AjaxControlToolkit.Common.Common.js
表4 ScriptManager.Scriptsプロパティに登録する内容

 Scriptsプロパティについては前回で既出であるが、実ファイルを直接参照する場合と異なり、アセンブリ内のスクリプトを取得するには(Pathプロパティではなく)Assembly/Nameプロパティで取得する必要があるので、注意されたい。

 あとは、ページ内のJavaScriptからBehaviorオブジェクトの場合と同様に、CommonToolkitScriptsクラスを利用することが可能だ。アセンブリに含まれるほかのBehaviorオブジェクトを利用する場合も同様の手続きで可能である。

要素にポップアップ機能を適用する

 次に、新規に生成された<div>要素に対してポップアップ機能を適用する。前述したように、ポップアップ機能を提供するのは、AjaxControlToolkit.PopupControlBehaviorクラスの役割だ。前回でも紹介したように、Behaviorオブジェクト(コンポーネント)を初期化するには、$createショートカット関数を利用すればよい。

 ここでは、AjaxControlToolkit.PopupControlBehaviorクラスに対して、以下のプロパティを指定して初期化しているわけだ。

プロパティ 概要
parentElement 親要素
positioningMode メッセージボックスの表示位置(ここでは親要素の右下)
表5 AjaxControlToolkit.PopupControlBehaviorクラスのプロパティ

 コンポーネントをインスタンス化できたら、後はshowメソッドでメッセージボックスをポップアップ表示することができる。また、メッセージボックスを非表示にするにはhideメソッドを呼び出せばよい。

[5]スタイルシートを用意する

 前述したように、DialogButtonExternalコントロールでは、メッセージボックスのスタイルを指定するためにCSSスタイルシートを利用している。ここでは、以下のようなスタイルシートを用意しておくものとしよう*4

*4 前述したように、スタイルシートのようなリソースはあらかじめソリューション・エクスプローラで「埋め込まれたリソース」として設定しておく必要があるので要注意。

.dialog
{
  width : 150px;
  background-color : white;
  background-image : url(<%= WebResource("MyAjaxLib.Back.jpg") %>);
  padding : 30px;
  border-style : ridge;
  border-width : 1px;
}
リスト7 DialogButtonExternalBehavior.jsから利用するCSSスタイルシート(Dialog.css)

 ここで注目していただきたいのは、リスト内の太字部分だ。ここでは、background-imageプロパティとしてメッセージボックスの背景画像を指定しているわけであるが、先にも見たように、背景画像(Back.jpg)はアセンブリ内のリソースとして登録されている。

 このような場合、(当然ながら)

background-image : url("Back.jpg");

のように指定しても、Back.jpgにアクセスすることはできない。アセンブリ内のリソースを参照するには、WebResourceプロパティでリソース参照のためのURLを動的に取得する必要があるのだ。

 WebResourceプロパティを呼び出すには、リソースの中で、

<%= WebResource("アセンブリ内のパス") %>

のように記述すればよい。これによって、<%= 〜 %>ブロックの中身は実行時に動的に解析され、出力時には、

background-image : url(WebResource.axd?d=jkvGDO72SbSg3XpmcPVdp_1HjDe1qeEXrkLClq08ong1&t=633332505949062500);

といったURLが埋め込まれることになる。

 ただし、先にも述べたように、リソース内で<%= 〜 %>ブロックを使用する場合には、エクステンダ・クラスの側でWebResource属性(PerformSubstitutionプロパティ)を付加しておく必要があるので注意してほしい。ここではスタイルシートに<%= 〜 %>ブロックを埋め込む方法について紹介したが、もちろん、JavaScriptファイルやテキスト・ファイルなど、そのほか任意のリソースに対しても、同じ要領で指定できる。

[6]DialogButtonExternalコントロールの動作を確認する

 以上で、DialogButtonExternalコントロールの実装の手順は完了だ。前回の手順に従って、DialogButtonExternalコントロールをWebサイトに配置した後、WebフォームからDialogButtonExternalコントロールの動作を確認してみよう。

 新規のWebフォーム(DialogButtonExternal.aspx)を作成したら、フォーム・デザイナから以下の図7の要領でサーバ・コントロールを配置する。また、それぞれのコントロールに対しては、表6の内容でプロパティ値を設定しておこう。


図7 Webフォーム(DialogButtonExternal.aspx)のレイアウト

コントロール名(ID値) プロパティ名 設定値
ScriptManager(manager)
Button(btnDialog) Text 表示切り替え
DialogButtonExternalExtender(dbee) Message こんにちは、MS AJAX Lib!
TargetControlID btnDialog
表6 図7で配置したコントロールとその設定

 以上の手順を終えたら、さっそく、DialogButtonExternal.aspxを実行してみよう。図3のように、[表示切り替え]ボタンをクリックすることで、オリジナルのポップアップ・メッセージボックスが表示/非表示されれば成功だ。

 以上、今回はExtenderコントロールにAjax機能を付与する方法、および既存のBehaviorオブジェクトを引用する方法について紹介した。特にControl Toolkitで提供されているBehaviorオブジェクトには有用なものが多く、駆使すれば、高度な処理をシンプルなコードで実現できるはずだ。

 もっとも、Control Toolkitで提供されているBehaviorオブジェクト(とその中に含まれる諸メソッド)の分量は膨大であり、本稿でそのすべてを紹介することはできない。興味のある方は、拙著『ASP.NET AJAXプログラミング − Windows標準AJAXフレームワークによるリッチクライアント開発手法− 』でもまとめているので、参照いただきたい。

 さて、次回は再びMS AJAX Lib単独の機能に戻って、JavaScriptプログラミングを効率化するさまざまなユーティリティ・クラスをTIPS的に紹介する予定だ。どうぞお楽しみに。End of Article

 

 INDEX
  Microsoft AJAX Library&JavaScriptプログラミング
  第4回 MS AJAX LibでAJAX対応コントロールを開発しよう(後編)
    1.Ajax対応のExtenderコントロールを作成しよう
    2.AjaxDialogButtonコントロールのBehaviorオブジェクト
    3.Control Toolkit標準のBehaviorオブジェクトを活用しよう
  4.DialogButtonExternalコントロールのBehaviorオブジェクト
 
インデックス・ページヘ  「Microsoft AJAX Library&JavaScriptプログラミング」


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メールマガジン 新着情報やスタッフのコラムがメールで届きます(無料)

注目のテーマ

Insider.NET 記事ランキング

本日 月間