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

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

山田 祥寛(http://www.wings.msn.to/
2007/12/21

■MyAjaxLib.DialogButtonBehaviorコンポーネントを定義する

 まずは、MyAjaxLib.DialogButtonBehaviorコンポーネントの定義からである。なお、本稿ではMS AJAX Libの基本的なオブジェクト指向構文については割愛するので、名前空間やクラス/メンバの定義については、第1回も併せて参照してほしい。

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

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

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

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

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

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

    // 基底クラスSys.Componentのinitializeメソッドをコール
    MyAjaxLib.DialogButtonBehavior.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) {

    // 設定値valueが元の値と異なる場合のみ、値をセット
    if (this._message !== value) {

      this._message = value;

      // Messageプロパティが変更されたことを通知
      this.raisePropertyChanged('Message');
    }
  },

  // Closedイベントを定義
  add_Closed : function(handler) {
    this.get_events().addHandler('Closed', handler);
  },

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

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

    // Messageプロパティの値をメッセージボックス表示
    window.alert(this._message);

    // Closedイベント・ハンドラを取得し、
    // 存在する場合にのみハンドラを呼び出し
    var h = this.get_events().getHandler('Closed');
    if (h) {
      h(this, Sys.EventArgs.Empty);
    }
  }
};

// Sys.UI.Behaviorクラスを継承する
// MyAjaxLib.DialogButtonBehaviorクラスを登録
MyAjaxLib.DialogButtonBehavior.registerClass(
  'MyAjaxLib.DialogButtonBehavior', Sys.UI.Behavior)
リスト1 MyAjaxLib.DialogButtonBehaviorクラスを定義するための「.js」ファイル(DialogButtonBehavior.js)

 コードの大まかな流れについては、リスト内のコメントを参照していただくとして、ここで注目していただきたいのは、以下の5点だ。

BehaviorオブジェクトはSys.UI.Behaviorクラスを継承する

 前項でも述べたように、任意の要素(ここではボタン)に対して特定の挙動を追加するためのコンポーネントを定義したい場合には、Sys.UI.Behaviorクラスを継承するべきだ。もちろん、Sys.Componentクラスを直接に継承しても構わないが、その場合、ターゲットとなる要素を設定/取得するためのコードを、自分で記述する必要がある(Sys.UI.Behaviorオブジェクトを継承した場合には、これらはすべてSys.UI.Behaviorオブジェクトによって賄われる)。

コンポーネントの初期化はinitializeメソッドで行う

 コンポーネントの初期化を行うには、Sys.Componentクラスで公開されているinitializeメソッドをオーバーライドすればよい。ここでは、ショートカット関数$addHandlerを利用して、ターゲット要素で発生したclickイベントに対して、イベント・ハンドラ「_onClick」(プライベート・メソッド)を関連付けているわけだ。

 なお、コンポーネントに関連付けられた要素(ターゲット要素)は、Sys.UI.Behaviorクラスのelementプロパティで取得することができる。

raisePropertyChangedメソッドでプロパティ値の変更を通知する

 MS AJAX Libでプロパティを定義する方法については、第1回でも述べたとおりだ。しかし、コンポーネント内のプロパティを定義する場合には、もう1点、注意すべき点がある。それがセッター・メソッド(setterメソッド)の内容――リスト1の の部分だ。ここでは、設定値と、もともとの値とが異なる場合にのみ代入処理を行い、かつ、raisePropertyChangedメソッドの呼び出しを行っている。

 raisePropertyChangedメソッドは、プロパティの値が変更されたことをコンポーネントに通知するためのメソッドである。対応する処理は、Sys.ComponentクラスのpropertyChangedイベント・ハンドラで定義することができる*1。本サンプルでは、特にプロパティの変更に応じた処理は行っていないので、raisedPropertyChangedメソッドの呼び出しは省略しても動作自体には影響しないが、コンポーネントの汎用性と今後の拡張を考えた場合、原則として、この部分の記述は欠かさないようにすることをお勧めしたい。

*1 propertyChangedイベント・ハンドラのシグニチャは、第2回でも述べたSys.WebForms.PageRequestManagerクラスのそれと同様だ。第2引数であるSys.EventArgs派生クラスを介してプロパティ名(propertyNameプロパティ)を取得できる。

add_Xxxxx/remove_Xxxxxメソッドでイベント・ハンドラを追加/削除する

 イベントに対応するイベント・ハンドラの追加/削除を行うのは、add_Xxxxx/remove_Xxxxxメソッド(「Xxxxx」の部分は実際にはイベント名となる)の役割だ。ここでは、Closedイベントに対応するadd_Closed/remove_Closedメソッドを定義している。

 コンポーネントに関連付いたイベント・ハンドラ(のリスト)を取得するには、Sys.Componentオブジェクトのeventsプロパティを参照すればよい。eventsプロパティは戻り値としてSys.EventHandlerListオブジェクトを返すので、後はこれを介して、addHandler/removeHandlerメソッドでそれぞれハンドラの追加/削除が可能だ。

 なお、addHandler/removeHandlerメソッドの第1引数に指定しているのは、コンポーネントの中でハンドラを一意に識別するための論理名である。論理名はコンポーネントの中で一意でありさえすれば任意の文字列を指定して構わないが、通常はイベント名を指定しておくのが無難だろう。

ターゲット・クリック時の挙動を定義する

 そして、ターゲット要素をクリックしたときの挙動を定義しているのが、リスト1の の部分である。ここでは、以下の2つの処理を行っている。

  • Messageプロパティで指定された文字列をメッセージボックスに表示
  • Closedイベント・ハンドラが登録されている場合には、これを実行

 登録済みのClosedイベント・ハンドラを取得するには、前述したSys.EventHandlerListオブジェクトを介してgetHandlerメソッドをコールすればよい。ここではgetHandlerメソッドの戻り値が空でない場合にのみ、これを実行しているわけだ。

 ここまでにも何度か見てきたように、イベント・ハンドラの引数には、

  • オブジェクト発生元のオブジェクト(つまり、thisキーワード)
  • イベント情報を表すSys.EventArgs派生オブジェクト

を設定するのが一般的だ。Sys.EventArgsオブジェクトには、必要に応じてイベントに関連する情報(例えばここでは、「メッセージボックスに表示したメッセージ」など)をセットし、イベント・ハンドラに引き渡すことも可能である。しかし、本サンプルでは特に引き渡したいイベント情報はないので、空のSys.EventArgsオブジェクトをセットしておくことにしよう。空のSys.EventArgsオブジェクトは、Sys.EventArgs.Emptyフィールドから取得することができる。

■Webフォームからコンポーネントを利用する

 以上で、MyAjaxLib.DialogButtonBehaviorクラス(コンポーネント)の定義は完了だ。次に、作成したコンポーネントをWebフォームから呼び出してみよう。ここで作成するWebフォームでは冒頭の図1でも示したように、以下の2つの動作を行う。

  • ボタン・クリック時に指定したメッセージをメッセージボックスに表示
  • メッセージボックスを閉じた後にページの背景色を青色に変化させる

[1]新規のWebフォームを作成する

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


図2 Webフォーム(DialogButton.aspx)のフォーム・レイアウト
配置するコントロールと、そのプロパティ設定は以下のとおり。

コントロール(ID) プロパティ 設定値
ScriptManager(manager) Scripts DialogButtonBehavior.js
Button(btnDialog) OnClientClick return false;
Text 表示
表3 図2で配置したコントロールとその設定

 ページ内で利用するMS AJAX Lib以外のJavaScriptコード(この場合はDialogButtonBehavior.js)は、あらかじめScriptManagerコントロールのScriptsプロパティに登録しておく必要がある。

 Scriptsプロパティを指定するには、プロパティ・ウィンドウでScriptsプロパティ右端の[...]をクリックすればよい。


図3 [ScriptReferenceコレクションエディタ]ダイアログ
ScriptManagerコントロールにリスト1(DialogButtonBehavior.js)を登録する。

 上の画面のような[ScriptReferenceコレクションエディタ]ダイアログが表示されるので、ダイアログ左下の[追加]ボタンをクリックし、右のプロパティ・グリッドからPathプロパティに「DialogButtonBehavior.js」へのパスを指定すればよい。

[2]コンポーネント呼び出しのコードを記述する

 次に、MyAjaxLib.DialogButtonBehaviorコンポーネントを呼び出し、実行するためのコードを、コード・エディタから記述する。具体的な追記部分は、以下のリスト2の白字部分だ。

</form>
<script type="text/javascript">
<!--

// アプリケーションを初期化
Sys.Application.initialize();

// ページ・ロード時に実行されるpageLoad関数を定義(連載第2回も参照)
function pageLoad() {

  // MyAjaxLib.DialogButtonBehaviorコンポーネントを生成
  $create(
    MyAjaxLib.DialogButtonBehavior,

    // プロパティ情報の定義
    {
      id : 'myDialog',
      Message : 'こんにちは、MS AJAX Lib!'
    },

    // イベント・ハンドラの定義
    {
      Closed : function() {
        document.bgColor = '#0000FF'; // 背景色を青色に変更
      }
    },
    null,

    // ターゲット要素の定義
    $get('btnDialog')
  );
}

//-->

</script>
</body>
リスト2 MyAjaxLib.DialogButtonBehaviorコンポーネントを呼び出すためのコード(DialogButton.aspx)
 

 コンポーネントをインスタンス化するのは、$createショートカット関数の役割だ*2。$create関数の一般的な構文は以下のとおりである。

*2 $create関数は、Sys.Component.createメソッドのエイリアス(別名)である。

$create(
   コンポーネントの型
  [, プロパティ情報(名前/値のハッシュ)
  [, イベント・ハンドラ情報(名前/ハンドラのハッシュ)
  [, ほかのコンポーネントへの参照
  [, コンポーネントを関連付けるターゲット要素]]]]
)
$create関数の構文

 上記の構文を踏まえてリスト2の内容を確認すると、ここでは、MyAjaxLib.DialogButtonBehaviorコンポーネントをButtonコントロール「btnDialog」に関連付けたうえで、id/Messageプロパティ、Closedイベント・ハンドラを定義していることになる。

 なお、プロパティ/イベント・ハンドラを指定するに際しては、「set_」「add_」などの接頭辞は不要である点に要注意だ。$create関数の中では、「Message」「Closed」のように、純粋なプロパティ名/イベント名を指定する必要がある。

 以上が理解できたら、さっそく作成したサンプル・プログラムを実行してみよう。冒頭の図1のように、ボタンをクリックするとメッセージボックスが表示され、さらにメッセージボックスを閉じたタイミングでページの背景が青色に変化することが確認できるはずだ。


 INDEX
  Microsoft AJAX Library&JavaScriptプログラミング
  第3回 MS AJAX LibでAJAX対応コントロールを開発しよう(前編)
    1.コンポーネント開発のための基本クラス/シンプルなコンポーネント
  2. MyAjaxLib.DialogButtonBehaviorを定義する/Webフォームから利用する
    3.Control Toolkitを利用したサーバ連携コントロールの開発
    4.エクステンダ・クラスを編集する/Behaviorオブジェクトを定義する
    5.Extenderコントロールを利用しよう
 
インデックス・ページヘ  「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 記事ランキング

本日 月間