次の方法で共有


非フォーム コントロールにおけるクライアント側の変更の永続化

クライアント側 ECMAScript (JScript、JavaScript) は、フォーム要素ではないコントロールにおけるクライアント側の状態変更を追跡するために使用できます。このようなコントロールでは、フォームを送信してもデータをサーバーに戻すことができません。イベントのポストバックは実行できますが、実行しても意味がないことがあります。この問題を解決するには、コントロールのデータを保持する非表示入力フィールドを使用します。コントロールは、非表示入力フィールドを作成し、フォームの送信前に状態情報を非表示フィールドに格納するスクリプトを出力する必要があります。コントロールが読み込まれたら、そのコントロールで非表示フィールドのデータを取得して使用できます。このような機構を実現するには、コントロールから PageRegisterHiddenField メソッドを呼び出して非表示フィールドを登録します。また、非表示フィールドの値を復元したりプロパティを更新したりするために、コントロールに IPostBackDataHandler インターフェイスを実装します。

このシナリオのサンプルを次に示します。このサンプルのコントロール (DHtmlControl) は、クライアントで選択されたときに色が変わるスパンを出力します。コントロールが登録する非表示変数の値は、クライアント側スクリプトによって、コントロールの選択状態を示すブール変数に設定されます。コントロールが公開するブール値のプロパティ (Selected) は、そのコントロールがクライアントで選択されたかどうかを示します。コントロールには IPostBackDataHandler インターフェイスが実装されているため、ページがサーバーにポストされたとき、コントロールで非表示フィールドの値を読み取ったり、コントロールの Selected プロパティを更新したりできます。さらに、コントロールは、クライアントでのコントロールの選択時に発生するイベント (SelectedChanged) も公開します。

このサンプルをビルドする方法については、「サーバー コントロールのサンプル」の手順を参照してください。

using System;
using System.Collections;
using System.Collections.Specialized;
using System.Drawing;
using System.Web;
using System.Web.UI;

namespace CustomControls
{
      public class DHtmlControl : Control, IPostBackDataHandler
      {
            public event EventHandler SelectedChanged;

            public string Text
            {
                  get
                  {
                        object obj = ViewState["Text"];
                        return (obj == null) ? String.Empty : (string)obj;
                  }

                  set
                  {
                        ViewState["Text"] = value;
                  }
            }

            public bool Selected
            {
                  get
                  {
                        object obj = ViewState["Selected"];
                        return (obj == null) ? false : (bool)obj;
                  }

                  set
                  {
                        ViewState["Selected"] = value;
                  }
            }

            protected string HelperID
            {
                  get
                  {
                        return "__" + ClientID + "_State";
                  }
            }

            protected override void OnInit(EventArgs e)
            {
                  base.OnInit(e);

                  if (Page != null)
                  {
                        Page.RegisterRequiresPostBack(this);
                  }
            }

            protected override void OnPreRender(EventArgs e)
            {
                  base.OnPreRender(e);

                  if (Page != null)
                  {
                        Page.RegisterHiddenField(HelperID, Selected.ToString());
                  }
            }

            protected override void Render(HtmlTextWriter writer)
            {
                  string postback = "";
                  if (Page != null)
                  {
                        postback = Page.GetPostBackEventReference(this) + ";";
                  }

                  string click = "onclick=\"var sel=getAttribute('selected'); sel = (sel.toLowerCase() == 'true'); sel=!sel; setAttribute('selected', sel.toString());this.style.backgroundColor=sel?'red':'white';" + HelperID +".value=sel.toString();" + postback + "\"";
                  string style = "style=\"cursor:hand;background-color:" + (Selected ? "red" : "white") + "\"";
                  string selected = "selected=\"" + Selected.ToString() + "\"";
                  writer.Write("<span " + style + " " + click + " " + selected + ">" + Text + "</span>");
            }

            bool IPostBackDataHandler.LoadPostData(string postDataKey, NameValueCollection postCollection)
            {
                  string value = postCollection[HelperID];

                  if (value != null)
                  {
                        bool newValue = (String.Compare(value, "true", true) == 0);
                        bool oldValue = Selected;

                        Selected = newValue;

                        // If there is a change, raise a change event.
                        return (newValue != oldValue);
                  }

                  return false;
            }

            void IPostBackDataHandler.RaisePostDataChangedEvent()
            {
                  // There was a change,  so raise any events.
                  if (SelectedChanged != null)
                  {
                        SelectedChanged(this, EventArgs.Empty);
                  }
            }
      }
}
[Visual Basic]
Option Explicit
Option Strict

Imports System
Imports System.Collections
Imports System.Collections.Specialized
Imports System.Drawing
Imports System.Web
Imports System.Web.UI
Imports Microsoft.VisualBasic

Namespace CustomControls
   Public Class DHtmlControl
      Inherits Control
      Implements IPostBackDataHandler
      Public Event SelectedChanged As EventHandler
      
      Public Property Text() As String
         Get
            Dim obj As Object = ViewState("Text")
            If obj Is Nothing Then
               Return String.Empty
            Else
               Return CStr(obj)
            End If
         End Get
         
         Set
            ViewState("Text") = value
         End Set
      End Property
      
      Public Property Selected() As Boolean
         Get
            Dim obj As Object = ViewState("Selected")
            If obj Is Nothing Then
               Return False
            Else
               Return CBool(obj)
            End If
         End Get
         
         Set
            ViewState("Selected") = value
         End Set
      End Property
      
      Protected ReadOnly Property HelperID() As String
         Get
            Return "__" & ClientID & "_State"
         End Get
      End Property
      
      Protected Overrides Sub OnInit(e As EventArgs)
         MyBase.OnInit(e)
         
         If Not (Page Is Nothing) Then
            Page.RegisterRequiresPostBack(Me)
         End If
      End Sub
      
      Protected Overrides Sub OnPreRender(e As EventArgs)
         MyBase.OnPreRender(e)
         
         If Not (Page Is Nothing) Then
            Page.RegisterHiddenField(HelperID, Selected.ToString())
         End If
      End Sub
      
      Protected Overrides Sub Render(writer As HtmlTextWriter)
         Dim postback As String = ""
         If Not (Page Is Nothing) Then
            postback = Page.GetPostBackEventReference(Me) & ";"
         End If
         
         Dim click As String = "onclick=""var sel=getAttribute('selected'); sel = (sel.toLowerCase() == 'true'); sel=!sel; setAttribute('selected', sel.toString());this.style.backgroundColor=sel?'red':'white';" & HelperID & ".value=sel.toString();" & postback & """"
         Dim style As String = "style=""cursor:hand;background-color:" & IIf(Selected, "red", "white").ToString() & """"
         Dim selectedPiece As String = "selected=""" & Selected.ToString() & """"
         writer.Write(("<span " & style & " " & click & " " & selectedPiece & ">" & Text & "</span>"))
      End Sub 
      
      Function LoadPostData(postDataKey As String, postCollection As NameValueCollection) As Boolean Implements IPostBackDataHandler.LoadPostData
         Dim value As String = postCollection(HelperID)
         
         If Not (value Is Nothing) Then
            Dim newValue As Boolean = String.Compare(value, "true", True) = 0
            Dim oldValue As Boolean = Selected
            
            Selected = newValue
            
            ' If there is a change, raise a change event.
            Return newValue <> oldValue
         End If
         
         Return False
      End Function
      
      Sub RaisePostDataChangedEvent() Implements IPostBackDataHandler.RaisePostDataChangedEvent
         ' There was a change, so raise any events.
         RaiseEvent SelectedChanged(Me, EventArgs.Empty)
      End Sub
   End Class 
End Namespace

DHTML コントロールを使用するページ

DHTML コントロールを使用し、イベント ハンドラを SelectedChanged イベントへアタッチするページを次に示します。コントロールはフォーム タグ内に記述されていますが、このコントロールはフォーム要素ではなく、サーバーにポストできる名前と値のペアを生成しません。

<%@Register TagPrefix="Custom" NameSpace="CustomControls" Assembly="CustomControls" %>
<script language="C#" runat = "server" >
private void SelectedChangedHandler(object sender, EventArgs e)
{
label.Text = "You selected the DHTML control";
}
</script>
<html>
 <body>  
    <form id="Form1" method="post" runat="server">
       <Custom:DHtmlControl OnSelectedChanged = "SelectedChangedHandler" runat="server" Text="SelectMe" />
       <br>
       <asp:Label id = "label" runat = "server" />
    </form> 
  </body>
</html>
[Visual Basic]
<%@Register TagPrefix="Custom" NameSpace="CustomControls" Assembly="CustomControls" %>
<script language="VB" runat = "server" >
    Private Sub SelectedChangedHandler(sender As Object, e As EventArgs)
       label.Text = "You selected the DHTML control"
    End Sub
</script>
<html>
 <body>  
    <form id="Form1" method="post" runat="server">
       <Custom:DHtmlControl OnSelectedChanged = "SelectedChangedHandler" runat="server" Text="SelectMe" />
       <br>
       <asp:Label id = "label" runat = "server" />
    </form> 
  </body>
</html>

参照

ポストバックのためのクライアント側スクリプトの生成