[SPRN05976]【Ajax】SPREADでコールバックを発生させるとSystem.Web.UI.ICallbackEventHandlerを使用したページのコールバックが動作しなくなる
対象製品
SPREAD for .NET 2.5J Web Forms Edition
発生環境
Visual Studio 2005
ASP.NET 2.0
ASP.NET 2.0
詳細
SPREADでコールバックを発生させるとSystem.Web.UI.ICallbackEventHandlerを使用したページのコールバックが動作しなくなります。
この動作はASP.NETにおけるイベントデータの検証がViewStateの値を対象としていることに起因します。
SPREADのコールバックではViewStateの内容を更新します。ASP.NETのイベントデータの検証はViewStateの値を元に行われますので、SPREADのコールバックによって更新されたViewStateの内容が検証違反となってしまいます。この動作は製品実装上の制限事項です。
下記、この現象の再現手順です。
[再現手順]
(1)WebフォームにSPREAD, TextBox, HTML Button 2個を配置します。
Button1: ASP.NET のICallbackEventHandlerでコールバックし
サーバー側で取得した現在時刻をフォーム上に表示します。
Button1のHTMLソースを次の様に設定します。
<input id="Button1" style="position: static" type="button" value="page.callback" onclick="doCallBack();"/>
Button2: SPREADでコールバックし、シートの背景色を変更します。
Button2のHTMLソースを次の様に設定します。
<input id="Button2" style="position: static" type="button" value="spread.callback" onclick="doFpCallBack();"/>
(2)ICallbackEventHandlerによるコールバックの結果を表示するために下記<SPAN>を追加します。
<span id="result" style="background-color:beige">result:</span>
(3)下記のコードとクライアント側スクリプトを追加します。
------------------------------------------
WebForm1.aspx.vb
------------------------------------------
Partial Class Default
Inherits System.Web.UI.Page
Implements System.Web.UI.ICallbackEventHandler
Public Function GetCallbackResult() As String Implements System.Web.UI.ICallbackEventHandler.GetCallbackResult
'コールバックレスポンスの設定
Dim result As String
result = DateTime.Now.ToLongTimeString
Return result
End Function
Public Sub RaiseCallbackEvent(ByVal eventArgument As String) Implements System.Web.UI.ICallbackEventHandler.RaiseCallbackEvent
'コールバックリクエストの取得
End Sub
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
'コールバックイベントの登録
Dim cbReference As String = Page.ClientScript.GetCallbackEventReference(Me, "arg", "receiveServerData", "context", "clientErrorCallback", False)
Dim callbackScript As String = "function CallServer(arg, context, clientError,isAsync) { " & cbReference & "} ;"
Page.ClientScript.RegisterClientScriptBlock(Me.GetType(), "CallServer", callbackScript, True)
'Me.EnableViewStateMac = False
End Sub
Protected Sub FpSpread1_ButtonCommand(ByVal sender As Object, ByVal e As FarPoint.Web.Spread.SpreadCommandEventArgs) Handles FpSpread1.ButtonCommand
'コールバックでシート背景色を変更する
If e.CommandName = "mycommand" Then
If e.SheetView.BackColor.Equals(System.Drawing.Color.Beige) Then
e.SheetView.BackColor = Drawing.Color.WhiteSmoke
Else
e.SheetView.BackColor = Drawing.Color.Beige
End If
End If
End Sub
End Class
---------------------------------------------
WebForm1.aspx
---------------------------------------------
<script type="text/javascript">
function doFpCallBack(){
var s=document.getElementById("FpSpread1");
s.CallBack("mycommand");//コールバック
}
function doCallBack(){
CallServer("","",clientErrorCallback,false);
}
function clientErrorCallback(arg,context){
alert(arg);
}
function receiveServerData(arg,context){
result.innerText=arg;
}
</script>
(4)実行します。
(5)Button1("page.callback")を複数回クリックします。
--- コールバックが発生し、表示時刻が更新されます。
(6)Button2("spread.callback")を複数回クリックします。
--- SPREADのコールバックが発生し、シート色が変更されます。
(7)Button1をクリックします。
--- コールバックが発生せず、時刻は更新されません。
この動作はASP.NETにおけるイベントデータの検証がViewStateの値を対象としていることに起因します。
SPREADのコールバックではViewStateの内容を更新します。ASP.NETのイベントデータの検証はViewStateの値を元に行われますので、SPREADのコールバックによって更新されたViewStateの内容が検証違反となってしまいます。この動作は製品実装上の制限事項です。
下記、この現象の再現手順です。
[再現手順]
(1)WebフォームにSPREAD, TextBox, HTML Button 2個を配置します。
Button1: ASP.NET のICallbackEventHandlerでコールバックし
サーバー側で取得した現在時刻をフォーム上に表示します。
Button1のHTMLソースを次の様に設定します。
<input id="Button1" style="position: static" type="button" value="page.callback" onclick="doCallBack();"/>
Button2: SPREADでコールバックし、シートの背景色を変更します。
Button2のHTMLソースを次の様に設定します。
<input id="Button2" style="position: static" type="button" value="spread.callback" onclick="doFpCallBack();"/>
(2)ICallbackEventHandlerによるコールバックの結果を表示するために下記<SPAN>を追加します。
<span id="result" style="background-color:beige">result:</span>
(3)下記のコードとクライアント側スクリプトを追加します。
------------------------------------------
WebForm1.aspx.vb
------------------------------------------
Partial Class Default
Inherits System.Web.UI.Page
Implements System.Web.UI.ICallbackEventHandler
Public Function GetCallbackResult() As String Implements System.Web.UI.ICallbackEventHandler.GetCallbackResult
'コールバックレスポンスの設定
Dim result As String
result = DateTime.Now.ToLongTimeString
Return result
End Function
Public Sub RaiseCallbackEvent(ByVal eventArgument As String) Implements System.Web.UI.ICallbackEventHandler.RaiseCallbackEvent
'コールバックリクエストの取得
End Sub
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
'コールバックイベントの登録
Dim cbReference As String = Page.ClientScript.GetCallbackEventReference(Me, "arg", "receiveServerData", "context", "clientErrorCallback", False)
Dim callbackScript As String = "function CallServer(arg, context, clientError,isAsync) { " & cbReference & "} ;"
Page.ClientScript.RegisterClientScriptBlock(Me.GetType(), "CallServer", callbackScript, True)
'Me.EnableViewStateMac = False
End Sub
Protected Sub FpSpread1_ButtonCommand(ByVal sender As Object, ByVal e As FarPoint.Web.Spread.SpreadCommandEventArgs) Handles FpSpread1.ButtonCommand
'コールバックでシート背景色を変更する
If e.CommandName = "mycommand" Then
If e.SheetView.BackColor.Equals(System.Drawing.Color.Beige) Then
e.SheetView.BackColor = Drawing.Color.WhiteSmoke
Else
e.SheetView.BackColor = Drawing.Color.Beige
End If
End If
End Sub
End Class
---------------------------------------------
WebForm1.aspx
---------------------------------------------
<script type="text/javascript">
function doFpCallBack(){
var s=document.getElementById("FpSpread1");
s.CallBack("mycommand");//コールバック
}
function doCallBack(){
CallServer("","",clientErrorCallback,false);
}
function clientErrorCallback(arg,context){
alert(arg);
}
function receiveServerData(arg,context){
result.innerText=arg;
}
</script>
(4)実行します。
(5)Button1("page.callback")を複数回クリックします。
--- コールバックが発生し、表示時刻が更新されます。
(6)Button2("spread.callback")を複数回クリックします。
--- SPREADのコールバックが発生し、シート色が変更されます。
(7)Button1をクリックします。
--- コールバックが発生せず、時刻は更新されません。
回避方法
次のいずれかの方法で回避できます。
●方法1●
ページのEnableEventValidationをFalseに設定します。
<%@ Page Language="VB" AutoEventWireup="false" CodeFile="TextBox.aspx.vb" Inherits="Default28" EnableEventValidation="false"%>
●方法2●
ページおよびSPREADのコールバックの際にそれぞれ「__EVENTVALIDATION」の値を設定します。
<script type="text/javascript">
var pageValidation = null;
var spreadValidation = null;
function initSpread() {
var txt = document.getElementById("__EVENTVALIDATION");
if (txt!=null) {
pageValidation = spreadValidation = txt.value;
}
}
function doFpCallBack(){
var txt = document.getElementById("__EVENTVALIDATION");
if (txt!=null) {
txt.value = spreadValidation;
}
var s=document.getElementById("FpSpread1");
s.CallBack("mycommand");//コールバック
if (txt!=null) {
spreadValidation = txt.value;
}
}
function doCallBack(){
var txt = document.getElementById("__EVENTVALIDATION");
if (txt!=null) {
txt.value = pageValidation;
}
CallServer("","",clientErrorCallback,false);
}
function clientErrorCallback(arg,context){
alert(arg);
var txt = document.getElementById("__EVENTVALIDATION");
if (txt!=null) {
txt.value = spreadValidation;
}
}
function receiveServerData(arg,context){
result.innerText=arg;
var txt = document.getElementById("__EVENTVALIDATION");
if (txt!=null) {
txt.value = spreadValidation;
}
}
</script>
<body onload="initSpread();">
●方法1●
ページのEnableEventValidationをFalseに設定します。
<%@ Page Language="VB" AutoEventWireup="false" CodeFile="TextBox.aspx.vb" Inherits="Default28" EnableEventValidation="false"%>
●方法2●
ページおよびSPREADのコールバックの際にそれぞれ「__EVENTVALIDATION」の値を設定します。
<script type="text/javascript">
var pageValidation = null;
var spreadValidation = null;
function initSpread() {
var txt = document.getElementById("__EVENTVALIDATION");
if (txt!=null) {
pageValidation = spreadValidation = txt.value;
}
}
function doFpCallBack(){
var txt = document.getElementById("__EVENTVALIDATION");
if (txt!=null) {
txt.value = spreadValidation;
}
var s=document.getElementById("FpSpread1");
s.CallBack("mycommand");//コールバック
if (txt!=null) {
spreadValidation = txt.value;
}
}
function doCallBack(){
var txt = document.getElementById("__EVENTVALIDATION");
if (txt!=null) {
txt.value = pageValidation;
}
CallServer("","",clientErrorCallback,false);
}
function clientErrorCallback(arg,context){
alert(arg);
var txt = document.getElementById("__EVENTVALIDATION");
if (txt!=null) {
txt.value = spreadValidation;
}
}
function receiveServerData(arg,context){
result.innerText=arg;
var txt = document.getElementById("__EVENTVALIDATION");
if (txt!=null) {
txt.value = spreadValidation;
}
}
</script>
<body onload="initSpread();">
この文書は、以前は次のFAQ IDで公開されていました : 6745