WebSurfer's Home

トップ > Blog 1   |   Login
Filter by APML

__doPostBack を使ってはいけません

by WebSurfer 21. April 2012 13:12

プログラマが、ASP.NET が自動生成する __doPostBack という名前の JavaScript 関数を、直接自分のコードに使ってはいけないという話です。

GridView で[選択]ボタンを使わないでポストバックをかけ、SelectedIndexChanged イベントで選択された行を取得

ASP.NET には、クライアントのイベントでサーバーにデータをポストバックするための、クライアントスクリプトを自動生成する機能があります。

それが表題の __doPostBack という名前の JavaScript の関数です。

例えば、GridView で、AutoGenerateSelectButton プロパティを true に設定すると[選択]ボタンが表示されますが、そのハイパーリンクに __doPostBack 関数が以下のように自動的に設定されます(ASP.NET 4 では ' はエスケープされて ' になります)。

<td>
  <a href="javascript:__doPostBack('GridView1','Select$0')">
    選択
  </a>
</td>

引数は、前者がデータを受け取って処置をするサーバーコントロールの UniqueID(上の例では GridView1)、後者がイベントデータ(上の例では Select$0 ⇒ 行インデックス 0 が Select されたという意味)になります。

__doPostBack 関数は、この 2 つの引数をそれぞれ __EVENTTARGET と __EVENTARGUMENT という id を持つ隠しフィールドに格納してから form を submit します。

この __doPostBack 関数や隠しフィールドは公開されてないので、将来なにもアナウンスされず変更される可能性があります。なので、プログラマがこの関数や隠しフィールドを使ってコーディングするのは避けた方がよさそうです。

代わりに、GetPostBackEventReference メソッドRaisePostBackEvent メソッド を使うのがお勧めです。

その例は、このブログの先の記事 CheckBox 付き Calendar コントロール でも紹介していますが、ここでも GridView を使って一例を紹介します。

上の画像は、GridView で[選択]ボタンを使わないで、行クリックでポストバックをかけ、SelectedIndexChanged イベントで選択された行を取得するサンプルです。__doPostBack 関数を直接使わないで、GetPostBackEventReference メソッドと RaisePostBackEvent メソッドを使って実現しています。

そのコードは以下の通りです。解説は、コードの中にコメントで書きましたので、そちらを参考にしてください。手抜きですみません。(笑)

実際に動かして試せるよう 実験室 にアップしましたので、興味のある方は試してみてください。

<%@ Page Language="C#" %>
<%@ Import Namespace="System.Data" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<script runat="server">

  // GridView で[選択]ボタンを使わないでポストバックをかけて
  // SelectedIndexChanged イベントで選択された行を取得。
  // ASP.NET AJAX の UpdatePanel を使っているのはオマケ。
    

  // 選択された行をチェックして SelectedIndexChanged イベント
  // を発生させるため RaisePostBackEvent メソッドを override 
  // する。そのため GridView を継承したカスタムコントロールを
  // 作る。
  public class MyGridView : GridView
  {
    // GetPostBackEventReference メソッドで設定したクライアント
    // スクリプト(この例では、下の myGridView_RowCreated イベ
    // ントハンドラで設定している)が起動されると、ポストバッ
    // クがかかり、サーバー側で RaisePostBackEvent メソッドが
    // 起動される。引数 arg には、クライアントスクリプトで設定
    // した GridView の行インデックスが渡される。
    protected override void RaisePostBackEvent(string arg)
    {
      int index;
      bool result = Int32.TryParse(arg, out index);

      if (result)
      {
        if (this.SelectedIndex != index)
        {
          this.SelectedIndex = index;
          this.OnSelectedIndexChanged(EventArgs.Empty);
        }
      }

      base.RaisePostBackEvent(arg);
    }        
  }
    
  // データソース用の DataTable を作成
  protected DataTable CreateDataTable()
  {
    DataTable dt = new DataTable();
    DataRow dr;

    dt.Columns.Add(new DataColumn("ID", typeof(Int32)));
    dt.Columns.Add(new DataColumn("Name", typeof(string)));
    dt.Columns.Add(new DataColumn("Price", typeof(Int32)));
    dt.Columns.Add(new DataColumn("Qty", typeof(Int32)));
    dt.Columns.Add(new DataColumn("Amount", typeof(Int32)));
    dt.Columns.Add(new DataColumn("Remarks", typeof(string)));

    for (int i = 0; i < 5; i++)
    {
      dr = dt.NewRow();
      dr["ID"] = i;
      dr["Name"] = "Item " + i.ToString();
      dr["Price"] = 123000 * (i + 1);
      dr["Qty"] = i + 1;
      dr["Amount"] = 123000 * (i + 1) * (i + 1);
      dr["Remarks"] = "Remarks " + i.ToString();
      dt.Rows.Add(dr);
    }
    return dt;
  }

  protected void Page_Load(object sender, EventArgs e)
  {
    MyGridView myGridView = new MyGridView();
    myGridView.ID = "myGridView1";
    myGridView.RowCreated += 
      new GridViewRowEventHandler(myGridView_RowCreated);
    myGridView.SelectedIndexChanged += 
      new EventHandler(myGridView_SelectedIndexChanged);
    TableItemStyle tableStyle = myGridView.SelectedRowStyle;
    tableStyle.BackColor = System.Drawing.Color.Blue;
    tableStyle.ForeColor = System.Drawing.Color.White;
        
    PlaceHolder1.Controls.Add(myGridView);
        
    if (!IsPostBack)
    {
      myGridView.DataSource = CreateDataTable();
      myGridView.DataBind();
    }
  }

  protected void myGridView_RowCreated(
    object sender, GridViewRowEventArgs e)
  {
    if (e.Row.RowType == DataControlRowType.DataRow)
    {
      // __doPostBack("<UniqueID>", "<RowIndex>") という
      // クライアントスクリプトの文字列が生成される。
      string script =
        Page.ClientScript.GetPostBackEventReference(
          (GridView)sender,
          e.Row.RowIndex.ToString());
            
      // データ行の tr 要素の onclick 属性に、上で生成
      // したスクリプトを設定する。
      e.Row.Attributes["onclick"] = script;
            
      // カーソルを指型にする
      e.Row.Style["cursor"] = "pointer";
    }
  }

  protected void myGridView_SelectedIndexChanged(
    object sender, EventArgs e)
  {
    Label1.Text = "SelectedIndex: " + 
      ((GridView)sender).SelectedIndex.ToString();
  }
   
</script>

<html xmlns="http://www.w3.org/1999/xhtml">
<head id="Head1" runat="server">
  <title></title>
</head>
<body>
  <form id="form1" runat="server">
  <asp:ScriptManager ID="ScriptManager1" runat="server">
  </asp:ScriptManager>
  <asp:UpdatePanel ID="UpdatePanel1" runat="server">
    <ContentTemplate>
      <asp:PlaceHolder ID="PlaceHolder1" 
        runat="server">
      </asp:PlaceHolder>
      <asp:Label ID="Label1" runat="server">
      </asp:Label>
    </ContentTemplate>
  </asp:UpdatePanel>
  </form>
</body>
</html>

Tags:

ASP.NET

About this blog

2010年5月にこのブログを立ち上げました。その後 ブログ2 を追加し、ここは ASP.NET 関係のトピックス、ブログ2はそれ以外のトピックスに分けました。

Calendar

<<  January 2021  >>
MoTuWeThFrSaSu
28293031123
45678910
11121314151617
18192021222324
25262728293031
1234567

View posts in large calendar