by WebSurfer
2013年1月27日 16:52
Ajax Control Toolkit の ModalPopup 内の iframe に別ページを表示し、その別ページに配置されているボタンをクリックして ModalPopup を非表示にする方法の紹介です。
ModalPopup はクライアントスクリプトで非表示にできます。それには、Modalpopup をページに配置するとダウンロードされるクライアントスクリプトに定義されている hide メソッドを使います。
従って、iframe に表示するページの適当な DOM に click イベントのリスナーを仕掛けて、それで hide メソッドを起動すれば ModalPopup を非表示にできます。
ただし、iframe に表示するページは親ページと同じドメインのものでないと DOM が取得できないので注意してください(クロスサイトスクリプト対策だそうです)。
そのサンプルコードを以下に書いておきます。また、実際に動かして試すことができるよう 実験室 にアップしました。興味のある方は試してみてください。
親ページ
<%@ Page Language="C#" %>
<%@ Register Assembly="AjaxControlToolkit"
Namespace="AjaxControlToolkit"
TagPrefix="asp" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<script runat="server">
</script>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title></title>
<script type="text/javascript">
//<![CDATA[
// iframe 内の document オブジェクトを取得。
// contentWindow は IE 用。
// contentDocument は Firefox 用。
function iframeRef(frameRef) {
return frameRef.contentWindow ?
frameRef.contentWindow.document :
frameRef.contentDocument;
}
function hideModalPopup() {
var modalPopup =
$find('programmaticModalPopupBehavior');
modalPopup.hide();
}
function showModalPopup() {
var ifm = iframeRef($get('iframe1'));
var btn = ifm.getElementById('hideButton');
// hide するとリスナーも解除されてしまうので、
// (btn.click が null になることで確認できる)
// ModalPopup を表示するたびリスナーをアタッチ
// する必要がある。
if (btn.onclick == null) {
if (window.addEventListener) {
btn.addEventListener('click',
hideModalPopup,
false);
} else if (window.attachEvent) {
btn.attachEvent('onclick',
hideModalPopup);
}
}
var modalPopup =
$find('programmaticModalPopupBehavior');
modalPopup.show();
}
//]]>
</script>
<style type="text/css">
/*Modal Popup*/
.modalBackground
{
background-color: Gray;
filter: alpha(opacity=70);
opacity: 0.7;
}
.popup
{
background-color: White;
}
</style>
</head>
<body>
<form id="form1" runat="server">
<asp:ToolkitScriptManager
ID="ToolkitScriptManager1"
runat="server">
</asp:ToolkitScriptManager>
<h1>ModalPopup Test</h1>
<asp:Button ID="DummyButton"
runat="server"
style="display: none;" />
<input type="button"
value="Show ModalPopup"
onclick="showModalPopup();" />
<asp:Panel
ID="Panel1"
runat="server"
CssClass="popup">
<iframe
id="iframe1"
src="190-PageIniframe.aspx">
</iframe>
</asp:Panel>
<asp:ModalPopupExtender
ID="ModalPopupExtender1"
runat="server"
TargetControlID="DummyButton"
BehaviorID="programmaticModalPopupBehavior"
BackgroundCssClass="modalBackground"
PopupControlID="Panel1">
</asp:ModalPopupExtender>
</form>
</body>
</html>
iframe に表示するページ
<%@ Page Language="C#" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<script runat="server">
</script>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title></title>
</head>
<body>
<form id="form1" runat="server">
<div>
<h1>Page in iframe</h1>
<input type="button"
id="hideButton"
value="Hide ModalPopup" />
</div>
</form>
</body>
</html>
by WebSurfer
2012年11月21日 21:37
Internet Explorer (IE) の「インターネットオプション」の「詳細設定」タブで、「HTTP 1.1 を使用する」のチェックを外すと、Ajax Control Toolkit が動かないという話の紹介です。(プロキシサーバー経由になる場合は「プロキシ接続で HTTP 1.1 を使用する」のチェックを外す)
ググって見つけた CodePlex のページ ToolkitScriptManager ignores accept-encoding http header を読んで原因がわかりました。
簡単に言うと、原因は、ToolkitScriptManager が常に gzip で圧縮したスクリプトファイルを送信するのに、IE は「HTTP 1.1 を使用する」にチェックを入れないと解凍しないことです。
詳しく書くと、以下の通りです。
-
ToolkitScriptManager は、Microsoft Ajax Library を外部スクリプトファイルとして HTTP ハンドラ経由でブラウザにダウンロードさせるため、script 要素の src 属性に ScriptResource.axd?d=...&t=... と設定した初期ページをブラウザに返します。
クエリ文字列のパラメータ d には、HTTP ハンドラが取得すべきファイルの指定と、送信時に圧縮するか否かの指示が含まれています。(パラメータ d, t の詳細については MSDN マガジンの ASP.NET AJAX アプリケーションの国際化 を見てください)
-
IE の設定で「HTTP 1.1 を使用する」にチェックが入っている場合、要求ヘッダには Accept-Encoding: gzip, deflate が含まれます。チェックを外すと Accept-Encoding は含まれなくなります。
ASP.NET 標準の ScriptManager の場合は、Accept-Encoding の有無を見て、初期ページに指定される ScriptResource.axd?d=...&t=... のパラメータ d を変えてきます。(Accept-Encoding が無ければ非圧縮、Accept-Encoding: gzip, deflate が含まれれば gzip 圧縮がパラメータ d に指定される)
-
ところが、Ajax Control Toolkit の ToolkitScriptManager の場合は、要求ヘッダに Accept-Encoding があってもなくても、初期ページに指定する ScriptResource.axd?d=...&t=... は同じです。パラメータ d は gzip 圧縮の指定となります。
つまり、IE の設定で「HTTP 1.1 を使用する」のチェックを外しても/外さなくても、サーバーからHTTP ハンドラ経由で受け取るスクリプトファイルは gzip で圧縮されたものになります。
-
一方、IE の設定で「HTTP 1.1 を使用する」のチェックを外すということは、IE では圧縮ファイルは解凍されないということを意味します。(応答ヘッダに Content-Encoding: gzip が含まれていても無視されます)。
-
結果、IE は Microsoft Ajax Library のスクリプトを解析できず、Ajax Control Toolkit が動かないということになります。(「文字が正しくありません。」とか「'Sys' は宣言されていません。」などのエラーが出ます)
IE8, IE9 で検証してみましたが、同じ問題が出ます。
いまどき「HTTP 1.1 を使用する」のチェックを外すことはないでしょうから実際に問題が出ることはなさそうですが、こういう問題もあるということは ASP.NET Web アプリケーションの開発者なら知っておいたほうがよさそうだと思って書いてみました。
03a316f0-bec5-4a9b-b6bc-68109b1d52fa|1|5.0
Tags: ACT, GZIP
AJAX
by WebSurfer
2012年4月14日 15:48
AJAX Control Toolkit (ACT) の AutoComplete を使ってみました。
実装は特に難しいことはなく、アットマーク・アイティの AutoComplete コントロールで Google サジェスト風なオートコンプリート機能を実装するには? を参考にすれば機能的には問題なく動くと思います。
ただし、スタイルを何も設定しないと、TextBox と候補リスト(AutoCompleteExtender が生成する ul, li 要素を使ったリスト)の間にスペースができてしまいます。理由は、ul 要素の Margin のトップが何故か 40px になっているからです。(IE9 の開発者ツールで「レイアウト」を見ると分かります)
スペースのできるのが気に入らない場合は、CompletionListCssClass プロパティに自分でスタイルを定義する必要があります。以下に、その例を書いておきます。
Web Form(.aspx)
CompletionListCssClass プロパティに設定するスタイルは、margin: 0px !important; とするだけではダメで、以下のように他の要素も定義しなおす必要があります。
下の例で、CompletionListItemCssClass と CompletionListHighlightedItemCssClass も設定してありますが、TextBox と候補リストの間のスペースの調整には必要ないです(オマケです)。
<%@ Page Language="C#" %>
<%@ Register Assembly="AjaxControlToolkit"
Namespace="AjaxControlToolkit" TagPrefix="ajaxToolkit" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<script runat="server">
</script>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title></title>
<style type="text/css">
.autocomplete
{
margin: 0px !important;
padding: 0px !important;
text-align: left;
color: WindowText;
overflow: auto;
border-color: ButtonShadow;
border-width: 1px;
border-style: solid;
list-style-type: none;
background-color: inherit;
height: 200px;
}
.autocomplete_item
{
color: WindowText;
background-color: Window;
padding: 1px;
}
.autocomplete_highlightedItem
{
color: Black;
background-color: rgb(255, 255, 153);
padding: 1px;
}
</style>
</head>
<body>
<form id="form1" runat="server">
<ajaxToolkit:ToolkitScriptManager
ID="ToolkitScriptManager1"
runat="server">
</ajaxToolkit:ToolkitScriptManager>
<asp:TextBox ID="TextBox1"
runat="server" Columns="50">
</asp:TextBox>
<ajaxToolkit:AutoCompleteExtender
ID="TextBox1_AutoCompleteExtender"
runat="server"
MinimumPrefixLength="2"
ServicePath="~/142-ACTAutoComplete.asmx"
TargetControlID="TextBox1"
ServiceMethod="GetList"
CompletionSetCount="20"
CompletionListCssClass="autocomplete"
CompletionListItemCssClass="autocomplete_item"
CompletionListHighlightedItemCssClass=
"autocomplete_highlightedItem">
</ajaxToolkit:AutoCompleteExtender>
</form>
</body>
</html>
Web サービス(.asmx)
Web サービスは、クライアントスクリプトから呼び出して、JSON 形式のデータを返すように、クラスに ScriptService 属性を追加するところがポイントです。
以下の例で、データベースは Microsoft が無償で提供している Northwind サンプルデータベースの Products テーブルを使用しています。
<%@ WebService Language="C#" Class="_142_ACTAutoComplete" %>
using System;
using System.Web;
using System.Web.Services;
using System.Web.Services.Protocols;
using System.Collections.Generic;
using System.Web.Configuration;
using System.Data;
using System.Data.SqlClient;
[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[System.Web.Script.Services.ScriptService]
public class _142_ACTAutoComplete : WebService
{
[WebMethod]
public string[] GetList(string prefixText, int count)
{
List<string> list = new List<string>();
string connString =
WebConfigurationManager.
ConnectionStrings["Northwind"].ConnectionString;
string query =
String.Format(
"SELECT TOP {0} ProductName FROM Products " +
"WHERE ProductName LIKE @ProductName", count);
SqlConnection connection = new SqlConnection(connString);
SqlCommand command = new SqlCommand(query, connection);
SqlParameter param =
new SqlParameter("@ProductName", SqlDbType.NVarChar, 40);
param.Value = "%" + prefixText + "%";
command.Parameters.Add(param);
try
{
connection.Open();
SqlDataReader reader = command.ExecuteReader();
while (reader.Read())
{
list.Add(reader.GetString(0));
}
}
finally
{
connection.Close();
}
return list.ToArray();
}
}