しかし、Webページに実装させてしまうと他のページで使い回しできない。汎用性を考えるのなら、Webユーザーコントロールに実装させる。また、Webユーザーコントロールにはロジックのみを実装し、HTML要素は配置しない。(ロジックのみにすることで、使い方が縛られず、色々なコントロールと組み合わせられる。)
以下に、クライアント コールバックのロジックを汎用的に提供するWebユーザーコントロールの作成方法を記述する。
[ サーバーサイドコード ]
まず、以下の5つのフィールドを用意する。
- 処理を開始するクライアント関数の名称フィールド
- 処理結果を実際に受け取るクライアント関数の名称フィールド
- 処理結果を受け取るクライアント関数(利用側が用意する関数)の名称フィールド
- 例外発生時に例外メッセージを受け取るクライアント関数(利用側が用意する関数)の名称フィールド
- 処理結果フィールド
フィールド1は、文字列"Begin"とthis.UniqueIDを結合させた文字列となる。フィールド2は文字列”End”とthis.UniqueIDを結合させた文字列となる。フィールド1とフィールド2が示すクライアント関数は、このコントロールのascxファイルに定義する。
フィールド3とフィールド4が示すクライアント関数は、初期値がnullで、このコントロールを利用する側が独自に用意することになる。
次に、以下の4つのプロパティを用意する。
- フィールド1の読み取り専用プロパティ
- フィールド2の読み取り専用プロパティ(可視性はプロテクト)
- フィールド3のプロパティ
- フィールド4のプロパティ
プロパティ1とプロパティ2は読み取り専用である。プロパティ2は可視性をプロテクトにすること。
プロパティ3とプロパティ4は、フィールドの説明にも書いたように、このコントロールを利用する側が値を設定することとなる。
次に、以下のイベントハンドラを用意する。
- Initイベントのハンドラ
Initイベントのハンドラでは、フィールド1とフィールド2の初期化を行う。Loadイベントではないので注意すること。
最後にIClientCallbackEventHandlerインターフェイスの各メソッドを実装する。
以下に、コード例を記述する。
AsyncAcquireHogeControl.ascx.cs // クライアント コールバックでHogeを取得するためのコントロール。
public partial class AsyncAcquireHogeControl : System.Web.UI.UserControl, ICallbackEventHandler
{
// 処理結果。
private string result = null;
// このコントロールに用意されている、処理を開始するクライアントスクリプト関数の名称の名称。
private string clientBeginFunction;
// このコントロールに用意されている、処理結果を受け取るクライアントスクリプト関数の名称。
private string clientEndFunction;
// 処理結果を受け取るクライアントスクリプト関数の名称。
private string clientReceptionFunction = null;
// 例外発生時に呼び出されるクライアントスクリプト関数の名称。
private string clientErrorFunction = null;
// このコントロールに用意されている、処理を開始するクライアントスクリプト関数の名称を取得する。
// このクライアントスクリプト関数は、一つの文字列型の引数を受け取る。引数には取得したいHogeの名称を指定する。
public string ClientBeginFunction
{
get
{
return this.clientBeginFunction;
}
}
// このコントロールに用意されている、処理結果を受け取るクライアントスクリプト関数の名称を取得する。
protected string ClientEndFunction
{
get
{
return this.clientEndFunction;
}
}
// 処理結果を受け取るクライアントスクリプト関数の名称を取得または設定する。
// このクライアントスクリプト関数には、一つのHoge型の引数を用意すること。引数には取得したHogeが渡される。
public string ClientReceptionFunction
{
get
{
return clientReceptionFunction;
}
set
{
clientReceptionFunction = value;
}
}
// 例外発生時に呼び出されるクライアントスクリプト関数の名称を取得または設定する。
// このクライアントスクリプト関数には、一つの文字列型の引数を用意すること。引数には例外メッセージが渡される。
public string ClientErrorFunction
{
get
{
return clientErrorFunction;
}
set
{
clientErrorFunction = value;
}
}
// 初期化イベントのハンドラ。
protected void Page_Init(object sender, EventArgs e)
{
this.clientBeginFunction = "Begin" + this.UniqueID;
this.clientEndFunction = "End" + this.UniqueID;
}
// コールバックイベントの結果を返す。
public string GetCallbackResult()
{
return this.result;
}
// コールバックイベントを処理する。
public void RaiseCallbackEvent(string eventArgument)
{
// eventArgument引数に対応するHogeを取得し、
// XMLデータに変換後、resultフィールドに格納する。
}
}
[ クライアントサイドコード ]
クライアントサイドには、以下の2つの関数を用意する。
- 処理を開始する関数
- 処理結果を受け取る関数
関数1は、プロパティ1の値("Begin" + this.UniqueID)を関数名とする。この関数は、this.Page.ClientScript.GetCallbackEventReferenceメソッドの戻り値で得られるスクリプト関数を実行する。GetCallbackEventReferenceメソッドのclientErrorCallback引数にはプロパティ4の値を渡す。
関数2は、プロパティ2の値("End" + this.UniqueID)を関数名とする。この関数は、引数でクライアント コールバックの処理結果をサーバーから取得し、プロパティ3に指定されているクライアント関数を呼び出す。この時、必要なら処理結果をわかりやすい形式に変換(XMLデータを、JavaScriptで定義したラッパークラスに変換する等)してからプロパティ3のクライアント関数に渡す。
以下に、コード例を記述する。
AsyncAcquireHogeControl.ascx <%@ Control Language="C#" AutoEventWireup="true" CodeFile="AsyncAcquireHogeControl.ascx.cs" Inherits="AsyncAcquireHogeControl" %>
<script type="text/javascript" src="Hoge.js"></script>
<script type="text/javascript">
function <%= this.ClientBeginFunction %>(arg)
{
<%= this.Page.ClientScript.GetCallbackEventReference(this, "arg", this.ClientEndFunction, "null", this.ClientErrorFunction, true) %>
}
function <%= this.ClientEndFunction %>(result, context)
{
<% if (!string.IsNullOrEmpty(this.ClientReceptionFunction)){ %>
var hoge = new Hoge();
hoge.readXml(result);
<%= this.ClientReceptionFunction %>(hoge);
<% } %>
}
</script>
作成したWebユーザーコントロールを利用するには、以下のような使い方をする。
Default.aspx<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" %>
<%@ register src="AsyncAcquireHogeControl.ascx" tagname="AcquireHoge" tagprefix="async" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
<title>クライアント コールバックのサンプル</title>
<async:AcquireHoge id="acquireHoge1" runat="server" ClientReceptionfunction="reception1" ClientErrorFunction="error" />
<async:AcquireHoge id="acquireHoge2" runat="server" ClientReceptionfunction="reception2" ClientErrorFunction="error" />
<script type="text/javascript">
function reception1(result)
{
document.getElementById("textBox1").value = result.name;
}
function reception2(result)
{
alert(result.name);
}
function error(message)
{
alert(message);
}
</script>
</head>
<body>
<form id="form1" runat="server">
<div>
<button id="button1" onclick="<%= this.acquireHoge1.ClientBeginFunction %>('Foo');" >
テキストボックスに表示
</button>
<input id="textBox1" type="text" />
<br />
<button id="button2" onclick="BeginacquireHoge2('Foo');" >
メッセージボックスに表示
</button>
</div>
</form>
</body>
</html>
button2のonclickで行っているように、クライアント コールバックの開始関数は、ClientBeginFunctionで取得する代わりに、コントロールのIDの先頭に"Begin"を結合した文字列を直接記述しても良い。
サーバー側(ASP.NET)では、型指定されたデータセットを用意して、DataSet.GetXml()メソッドでXMLデータを生成するのが手っ取り早い。XML DOMを利用する方法もある。
クライアント側(JavaScript)では、XMLデータのラッパークラスを用意する。XMLデータの解析にはXML DOMを使用する。
ASP.NET Web ページでポストバックせずにクライアント コールバックを実装する
http://msdn2.microsoft.com/ja-jp/library/ms178208.aspx
ページをリロードせずにサーバーとやり取りする方法
http://www.microsoft.com/japan/msdn/asp.net/tips/ClientCallback/
クライアント・コールバックで複数の値をクライアントへ渡す方法
http://www.microsoft.com/japan/msdn/asp.net/tips/ClientCallback2/