WebSurfer's Home

トップ > Blog 1   |   Login
Filter by APML

UpdatePanel へのトリガ追加

by WebSurfer 6. November 2010 19:08

2010/11/8 追記

MSDN ライブラリの AsyncPostBackTrigger クラス の説明によると、"AsyncPostBackTrigger コントロールのプログラムによる追加はサポートされていません。" とのことです。というわけで、以下の方法はボツです。(汗) 別の方法で書き換えたものを UpdatePanel へのトリガ追加(改版) にポストしましたのでそちらを見てください。

AsyncPostBackTrigger を動的に設定

ASP.NET AJAX Extensions の UpdatePanel コントロールのトリガに AsyncPostBackTrigger クラスの ControlID として Button などのコントロールを動的に設定する話です。

大体のケースでは静的に設定できると思いますが、UniqueID を設定しなければならない場合は話が別です。

UniqueID を設定する必要があるのは、トリガとなる Button などのコントロールが名前付けコンテナに含まれ、ID とは異なる一意の UniqueID がサーバー側で設定される場合です。

名前付けコンテナとは、例えば、Repeater, DataList, DetailsView, FormView, GridView などやマスタページの ContentPlaceHolder です。

そのような場合に、AsyncPostBackTrigger クラスの ControlID プロパティに(UniqueID ではなく)ID を設定すると、「UpdatePanel 'UpdatePanel1' のトリガ用の ID 'Button1' のコントロールが見つかりませんでした。」というようなエラーが出るはずです。

というわけで本来は UniqueID を設定しなければなりませんが、UniqueID はサーバー側で生成されますので、サーバー側で動的に設定した方が簡単そうです。

ただし、タイミングが問題です。自分が試した限りですが、Page_Load ではうまくいかず、Page_Init でないとダメでした。(Page_Load で設定すると UpdateMode="Conditional" ではスクリプトエラー、デフォルトの Always にすればスクリプトエラーは出ないものの偶数回目のクリックで全画面が更新されてしまうというように、期待した動きにはなりません)

しかしながら、目的の(トリガとする)コントロールの参照が Page_Init では取得できない場合が困ります。例えば DetailesView の Template 内に配置したコントロールを FindControl メソッドで取得しようとしても、Page_Init では取得できません。

で、どうするかと言えば、ちょっとハック的なやり方ですが、Page_Init ではダミーのコントロールを設定し、Page_Load で目的のコントロールを設定するとうまくいきました。

DetailsView の Template に配置した Button を、AsyncPostBackTrigger クラスの ControlID プロパティに設定するサンプルを以下にアップしておきます。

<%@ 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">

  protected void Page_Init(object sender, EventArgs e)
  {
    // ここでは LinkButton1 取得できない。以下は常に null。
    // それはよしとして、不可解なのは、以下の一文を入れて
    // おくと LinkButton1 クリックで、DetailsView が消えて
    // しまうこと。何故???
    //LinkButton lb =
    //  (LinkButton)DetailsView1.FindControl("LinkButton1");

    // この時点でダミーでもいいから以下のように Trigger を追
    // 加しておかないとうまくいかない。これなしでページロード
    // でトリガを追加すると、LinkButton1 クリックでスクリプト
    // エラーとなる。
    AsyncPostBackTrigger trigger = new AsyncPostBackTrigger();
    trigger.ControlID = DummyButton.ID;
    UpdatePanel2.Triggers.Add(trigger);
  }

  protected void Page_Load(object sender, EventArgs e)
  {
    LinkButton lb = 
      (LinkButton)DetailsView1.FindControl("LinkButton1");
    if (lb != null)
    {
      AsyncPostBackTrigger trigger = new AsyncPostBackTrigger();

      // DetailsView に配置したボタンは UniqueID を持つ。
      // それを ControlID に設定しないとエラーになる。
      trigger.ControlID = lb.UniqueID;
      UpdatePanel2.Triggers.Add(trigger);
    }        
  }    

  protected void LinkButton1_Click(object sender, EventArgs e)
  {
    Label1.Text = DateTime.Now.ToString();
  }
</script>

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
  <title>AsyncPostBackTrigger を動的に設定</title>
</head>
<body>
  <form id="form1" runat="server">
  <asp:ScriptManager ID="ScriptManager1" runat="server">
  </asp:ScriptManager>

  <asp:SqlDataSource ID="SqlDataSource1" runat="server" 
    ConnectionString="<%$ ConnectionStrings:MyDB %>" 
    SelectCommand="SELECT [id], [name], [price] FROM [table]" >
  </asp:SqlDataSource>

  <asp:Button ID="DummyButton" 
    runat="server" 
    style="display: none;" />
  <h2>AsyncPostBackTrigger を動的に設定</h2>
  <h3>DetailsView</h3>
  <asp:UpdatePanel ID="UpdatePanel1" runat="server">
    <ContentTemplate>
      <asp:DetailsView ID="DetailsView1" 
        runat="server" 
        AutoGenerateRows="False" 
        DataKeyNames="id" 
        DataSourceID="SqlDataSource1" 
        EnableModelValidation="True" 
        AllowPaging="True" 
        Width="250px">
        <Fields>
          <asp:BoundField DataField="id" 
            HeaderText="id" 
            InsertVisible="False" 
            ReadOnly="True" 
            SortExpression="id" />
          <asp:BoundField DataField="name" 
            HeaderText="name" 
            SortExpression="name" />
          <asp:BoundField DataField="price" 
            HeaderText="price" 
            SortExpression="price" />
          <asp:TemplateField ShowHeader="False">
            <ItemTemplate>
              <asp:LinkButton ID="LinkButton1" 
                runat="server" 
                CausesValidation="False" 
                Text="Show Current Time" 
                OnClick="LinkButton1_Click">
              </asp:LinkButton>
            </ItemTemplate>
          </asp:TemplateField>
        </Fields>
      </asp:DetailsView>            
    </ContentTemplate>
  </asp:UpdatePanel>
  <hr />
  <h3>Time</h3>
  <asp:UpdatePanel ID="UpdatePanel2" 
    runat="server" 
    UpdateMode="Conditional">
    <ContentTemplate>
      <asp:Label ID="Label1" 
        runat="server" 
        Text="[time]" />
    </ContentTemplate>
  </asp:UpdatePanel>
  </form>
</body>
</html>

Tags: , ,

AJAX

About this blog

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

Calendar

<<  June 2021  >>
MoTuWeThFrSaSu
31123456
78910111213
14151617181920
21222324252627
2829301234
567891011

View posts in large calendar