はじめ
にWeb アプリケーションのフォーム送信プロセス中に、特に送信プロセスに時間がかかる場合に、「お待ちください」メッセージやアニメーション GIF イメージを表示すると便利なことがよくあります。私は最近、内部ユーザーが Web ページ経由で Excel スプレッドシートをアップロードするアンケート送信プログラムを開発しました。プログラムは、アップロードされたスプレッドシート データをデータベースに挿入します。このプロセスには数秒しかかかりませんが、たとえ数秒だったとしても、Web ページの観点からは非常に明らかな待機プロセスです。プログラムのテスト中に、一部のユーザーがアップロード ボタンを繰り返しクリックしました。したがって、アップロードが進行中であることを伝える視覚的なメッセージを提供すると便利です。また、複数のクリックを防ぐために、同時にアップロード ボタンを非表示にします。ここで紹介するコントロールは Button コントロールのサブクラスであり、クライアント側の JavaScript コードを ASP.NET サーバー コントロールにカプセル化して便利な機能を提供する方法を示します。
これを実現するための JavaScript の例は数多くありますが、これらの関数を ASP.NET コントロールにカプセル化しようとすると、いくつかの問題が見つかりました。まず、JavaScript の onclick ハンドラーを使用してボタンを無効にし、他のテキストに置き換えようとしました。しかし、これはasp.netサーバー側のクリックイベントの機能を妨げるため、これは非常に難しいことがわかりました。最終的に機能し、さまざまなブラウザを適切にサポートできるようになったのは、ボタンを div タグでレンダリングすることでした。 div は非表示にして、asp.net のクリック イベントの邪魔にならないようにすることができます。
コントロールの使用方法
通常のボタン コントロールから派生したものである PleaseWaitButton の機能は基本的に同じです。 3 つの追加プロパティを使用して、ボタンがクリックされたときの「お待ちください」メッセージまたは画像の表示を管理します。
お待ちくださいテキスト
これは表示されるクライアント側のテキスト メッセージであり、存在する場合は、ボタンがクリックされたときにボタンを置き換えます。
お待ちください画像
これは表示される画像ファイル (アニメーション GIF 画像など) であり、存在する場合は、クリックされたときにボタンを置き換えます。この属性は、<img> タグの src 属性になります。
お待ちくださいタイプ
PleaseWaitTypeEnum 列挙値のいずれか: TextOnly、ImageOnly、TextThenImage、または ImageThenText。メッセージと画像のレイアウトを制御します。
以下は、PleaseWaitText と PleaseWaitImage が設定された PleastWaitButton を示す .aspx ファイルの例です。
<%@ ページ言語="C#" %>
<%@ 登録 TagPrefix="cc1" 名前空間="JavaScriptControls"
Assembly="PleaseWaitButton" %>
<script runat="server">
private void PleaseWaitButton1_Click(オブジェクト送信者、System.EventArgs e)
{
// サーバー側の Click イベント ハンドラー。
// 長い時間がかかる可能性のあるものをシミュレートします。
// ファイルのアップロードや時間のかかるサーバー処理など
DateTime dt = DateTime.Now.AddSeconds(5);
while (DateTime.Now < dt)
{
// 何も行わず、5 秒間の一時停止をシミュレートします。
}
// ループの最後に成功メッセージを表示します
// 送信フォームを非表示にします
パネル成功.Visible = true;
PleaseWaitButton1.Visible = false;
}
</script>
<html>
<頭>
<title>PleaseWaitButton をテストしています</title>
</head>
<本文>
<form id="Form1" Method="post" runat="server">
<P>PleaseWaitButton コントロールをテストしています。</p>
<cc1:PleaseWaitButton id="PleaseWaitButton1" runat="サーバー"
Text="クリックして時間のかかるプロセスを開始してください"
PleaseWaitText="お待ちください "
PleaseWaitImage="PleaseWait.gif"
OnClick="PleaseWaitButton1_Click" />
<asp:Panel id="panelSuccess" runat="server"
可視 = false">
このフォームを送信していただきありがとうございます。
私がこれまでサービスをさせていただいた中で最もクールなユーザーです。
いや、本当にそう言いたいのですが、確かに他にもありました。
しかし、あなたは本当に一人で授業を受けています。
</asp:パネル>
</form>
</body>
</html>
仕組み
PleaseWaitButton コントロールは、<div> タグ内に標準の ASP.NET ボタンをレンダリングします。また、情報/画像の空の <div> タグもレンダリングされます。ボタンをクリックすると、ボタンの非表示と情報の表示が Javascript 関数によって制御されます (下記のクライアント関数を参照)。便宜上、必要なすべての JavaScript クライアント コードの実装は PleaseWaitButton サーバー コントロールによって処理されます。
PleaseWaitButton は独自の JavaScript onclick ハンドラーを実装しているため、元の onclick ハンドラーを保持し、コントロールがクライアント側の検証コードを正常に実行できるようにするために、いくつかの追加の手順を実行する必要があります。この目標を達成するために、まず Button の基本クラスを文字列バッファに復元し、それからそれを巧みに処理して、定義した onclick コードを含めます。
protected オーバーライド void Render(HtmlTextWriter 出力)
{
// ボタンの HTML を出力します (属性付き)
// ダミーの HtmlTextWriter に
StringWriter sw = 新しい StringWriter();
HtmlTextWriter wr = 新しい HtmlTextWriter(sw);
Base.Render(wr);
文字列 sButtonHtml = sw.ToString();
wr.Close();
sw.Close();
// コードを変更して「onclick」ハンドラーを含めます
// PleaseWait() 関数が適切に呼び出されます
// クライアント側の検証後。
sButtonHtml = ModifyJavaScriptOnClick(sButtonHtml);
// ボタンをレンダリングする前に、空の <div> を出力します。
// JavaScript を介してクライアント側に設定されます
// 「お待ちください」メッセージ付き
Output.Write(string.Format("<div id='pleaseWaitButtonDiv2_{0}'>",
this.ClientID));
Output.Write("</div>");
// ボタンを独自のカプセル化 <div> タグ内にレンダリングします。
Output.Write(string.Format("<div id='pleaseWaitButtonDiv_{0}'>",
this.ClientID));
出力.Write(sButtonHtml);
Output.Write("</div>");
}
ボタンを文字列バッファーに減らしてその onclick コンテンツを処理するこの手法は確かにハックですが、これにより、親ボタン クラスに標準の検証コードを実装してから、PleaseWait() JavaScript 関数呼び出しを実装することができます。これを行わないと、親 Button クラスの属性のレンダリングを完全にオーバーライドしない限り、検証コードの前に onclick 属性で PleaseWait() 関数呼び出しを実装する必要があります。こうすることで、ページ上で入力ミスがあってもボタンを非表示にして、望ましくない「お待ちください」メッセージが表示されるという効果が得られます。したがって、クライアント ページの検証後に onclick ハンドラーでクライアントの PleaseWait() 関数を強制的に表示する必要があります。
onclick 属性の変更は、ModifyJavaScriptOnClick() 関数で行われます。この関数は、ボタンによってレンダリングされた HTML 文字列を取得し、onclick 属性が存在するかどうかを確認します。使用されている場合、この関数はクライアント側の検証コードが使用されているかどうかをチェックします。この場合、定義した PleaseWait() 関数は、既存の onclick コードの最後、クライアントによってチェックされたブール変数 Page_IsValid の直後に追加されます。この変数は、検証コントロールが使用されるかどうかを表します。 Page_IsValid の値が false の場合、「お待ちください」メッセージは表示されません。 True の場合に表示されます。
プライベート文字列 ModifyJavaScriptOnClick(文字列 sHtml)
{
// CodeProject メンバー KJELLSJ (Kjell-Sverre Jerijaervi) に感謝します
// ボタンがクライアント側の検証
文字列で動作できるようにするコードのアイデアについては、 sReturn = "";
string sPleaseWaitCode = GeneratePleaseWaitJavascript();
// 既存の onclick 属性はありますか?
Regex rOnclick = new Regex("onclick="(?<onclick>[^"]*)");
マッチ mOnclick = rOnclick.Match(sHtml);
if (mOnclick.成功)
{
// 既存の onclick 属性があります。
// クライアント側の場合はコードを末尾に追加します。
// 検証がレンダリングされたことを確認してください
// ページが有効かどうかを確認します。
文字列 sExisting = mOnclick.Groups["onclick"].Value;
文字列 sReplace = sExisting
+ (sExisting.Trim().EndsWith(";") ? "" : "; ");
if (IsValidatorIncludeScript() && this.CausesValidation)
{
// ページが有効かどうかを確認するコードを含めます
文字列 sCode = "if (Page_IsValid) " + sPleaseWaitCode
+ " Page_IsValid を返します;";
// コードを既存の onclick コードの末尾に追加します。
sReplace = sReplace + sCode;
}
それ以外
{
// ページが有効であるかどうかを心配する必要はありません。
sReplace = sReplace + sPleaseWaitCode;
}
// ここで、onclick コードを置き換えます
sReplace = "onclick="" + sReplace;
sReturn = rOnclick.Replace(sHtml, sReplace);
}
それ以外
{
// 既存の onclick 属性はありません。
// 私たちのものを追加します
int i = sHtml.Trim().Length - 2;
string sInsert = " onclick="" + sPleaseWaitCode + "" ";
sReturn = sHtml.Insert(i, sInsert);
}
、
上記のチェックを使用して、
asp.net 検証コントロールの標準 Javascript コード ブロックがページに登録されているかどうかを確認します。以下では、簡単な方法を使用して、検証コードと Page_IsValid などの変数があるかどうかをテストします。
private bool IsValidatorIncludeScript()
{
// このページに JavaScript が登録されている場合は TRUE を返します
// クライアント側の検証では、このコードは登録されない可能性があります。
// ASP.NET が考えたことを (正しくまたは間違って) 検出した場合
// ダウンレベルのブラウザです
return this.Page.IsStartupScriptRegistered("ValidatorIncludeScript");
次の GeneratePleaseWaitJavascript() は、onclick 属性に含まれる PleaseWait() JavaScript 関数を構築します。コントロールのプロパティを調べることで、目的のレイアウトを決定できます。
プライベート文字列 GeneratePleaseWaitJavascript()
{
// JavaScript「PleaseWait()」関数呼び出しを作成します
// onclick イベント ハンドラーでの使用に適しています
string sMessage = "";
文字列 sText = _pleaseWaitText;
string sImage = (_pleaseWaitImage != String.Empty
? string.Format(
"<img src="{0}" align="absmiddle" alt="{1}"/>"
、_pleaseWaitImage、_pleaseWaitText )
: String.Empty);
// PleaseWaitType に基づいてレイアウトを確立します
スイッチ (_pleaseWaitType)
{
ケースPleaseWaitTypeEnum.TextThenImage:
sMessage = sText + sImage;
壊す;
ケースPleaseWaitTypeEnum.ImageThenText:
sMessage = sImage + sText;
壊す;
ケースPleaseWaitTypeEnum.TextOnly:
sメッセージ = sテキスト;
壊す;
ケースPleaseWaitTypeEnum.ImageOnly:
sメッセージ = sイメージ;
壊す;
}
// 最終的なコードチャンクを返す
文字列 sCode = string.Format(
"PleaseWait('PleaseWaitButtonDiv_{0}',
'pleaseWaitButtonDiv2_{1}', '{2}');"
、this.ClientID、this.ClientID、sMessage);
sCode = sCode.Replace(""", """);
sCode を返します。
}
PleaseWaitImage を指定する場合は、クライアントに画像をプリロードするように通知する追加の JavaScript コードを含める必要があります。このスクリプトの登録は、オーバーライドされた OnPreRender メソッドに表示される必要があります。登録されたキーはイメージの名前です。複数のボタンが同じイメージを使用する場合、プリロード スクリプトは 1 回だけ実装する必要があります。ここでは正規表現を使用して Javascript イメージ変数を作成し、特殊文字 (ファイル パスのスラッシュなど) が確実にアンダースコアに変換されるようにします。
protected オーバーライド void OnPreRender(EventArgs e)
{
Base.OnPreRender (e);
// 画像を使用している場合は、JavaScript を登録します。
// クライアント側のイメージのプリロード用
if (_pleaseWaitImage != String.Empty
&& _pleaseWaitType != PleaseWaitTypeEnum.TextOnly)
RegisterJavascriptPreloadImage(_pleaseWaitImage);
private void RegisterJavascriptPreloadImage(string sImage
)
{
Regex rex = new Regex("[^a-zA-Z0-9]");
文字列 sImgName = "img_" + rex.Replace(sImage, "_")
;
sb.Append("<script language='JavaScript'>");
sb.Append("if (document.images) { ");
sb.AppendFormat("{0} = 新しい画像();", sImgName);
sb.AppendFormat("{0}.src = "{1}";", sImgName, sImage);
sb.Append(" } ");
sb.Append("</script>");
this.Page.RegisterClientScriptBlock(sImgName + "_PreloadScript",
sb.ToString());
クライアント側の関数
埋め込み
テキスト ファイル javascript.txt には、ボタンを非表示にする <div> と、「お待ちください」メッセージまたは画像を表示するクライアント側のコードが含まれています。これらのコードは、オーバーライドされた OnInit() メソッドで呼び出されるプライベート メソッド RegisterJavascriptFromResource() にロードされます。このメソッドは汎用メソッド GetEmbeddedTextFile() を呼び出します。このメソッドは、ファイルをソースとしてロードし、コンテンツを文字列として返します。
protected オーバーライド void OnInit(EventArgs e)
{
Base.OnInit(e);
// クライアント側の JavaScript コードは保持されます
// 埋め込みリソース内でスクリプトをロードします。
// そしてページに登録します。
RegisterJavascriptFromResource();
}
private void RegisterJavascriptFromResource()
{
// 埋め込みテキストファイル「javascript.txt」を読み込みます
// そしてその内容をクライアント側スクリプトとして登録します
文字列 sScript = GetEmbeddedTextFile("javascript.txt");
this.Page.RegisterClientScriptBlock("PleaseWaitButtonScript", sScript);
}
プライベート文字列 GetEmbeddedTextFile(string sTextFile)
{
// コンテンツを取得するための汎用関数
// 埋め込みテキスト ファイル リソースを文字列として
// 実行中のアセンブリを取得し、派生します
// アセンブリ内の最初の型を使用する名前空間
アセンブリ a = Assembly.GetExecutingAssembly();
String sNamespace = a.GetTypes()[0].Namespace
// アセンブリと名前空間を使用して、
//埋め込みリソースをストリームとして
ストリーム s = a.GetManifestResourceStream(
string.Format("{0}.{1}", sNamespace, sTextFile)
);
// ストリームの内容を文字列に読み込みます
StreamReader sr = 新しい StreamReader;
文字列 sContents = sr.ReadToEnd()
;
s.Close();
sContents を返します。
}
javascript.txt 埋め込みリソースには、ボタンの Javascript onclick ハンドラーで実行されるクライアント側メソッド PleaseWait() が含まれています。また、このコードは、クライアント側のメソッド HideDiv() を呼び出してボタンのコンテナ <div> を非表示にし、innerHTML 属性を設定して情報または画像を以前は空だった <div> タグに組み込みます。補助関数 GetDiv() は、document.getElementById、document.all、および document.layers をチェックして ID を持つ <div> オブジェクトを返し、さまざまなブラウザーとの互換性を確保します。以下は javascript.txt のコード全体です。
<スクリプト言語="JavaScript">
関数 GetDiv(sDiv)
{
ヴァルディブ;
if (document.getElementById)
div = document.getElementById(sDiv);
else if (document.all)
div = eval("ウィンドウ。" + sDiv);
else if (document.layers)
div = document.layers[sDiv];
それ以外
div = null
を返します。
関数
HideDiv(sDiv)
{
d = GetDiv(sDiv);
もし(d)
{
if (document.layers) d.visibility = "非表示";
それ以外の場合は d.style.visibility = "非表示";
}
関数
PleaseWait(sDivButton, sDivMessage, sInnerHtml)
{
HideDiv(sDivButton);
var d = GetDiv(sDivMessage);
if (d) d.innerHTML = sInnerHtml;
}
</script>
元のリンク: http://www.codeproject.com/aspnet/PleaseWaitButton.asp
ソース プロジェクトのダウンロード - 7 KB
デモ プロジェクトのダウンロード - 30 Kb
http://www.cnblogs.com/jeffamy/archive/2006/08/20/481952.html