7

ユーザーが自分のWebサイト構造を設計できるようにするコントロールを作成したいと思います。UpdatePanel内部にはTextBox(ページ名に)とButton「下に追加」が付いたコントロールがあると想像しました。次のようになります。

|   "Questions" |
| [ add below ] |

|     "Tags"    |
| [ add below ] |

|    "Badges"   |
| [ add below ] |

これで、ユーザーが「タグ」要素のボタンをクリックすると、「タグ」と「バッジ」の間に編集可能な名前の新しいボタンが表示されるはずです。たとえば、ユーザーは「ユーザー」という名前を付けることができます。(ページの点滅を避けるために)完全なポストバックなしで実行する必要があります。

今が私の問題です。これらのコントロール(すべてではありません)は存在しないため、onInitにロードできませんが、クリックイベントに参加する必要があるため、Initフェーズで実行する必要があるイベントリスナーをアタッチする必要があります。説明されている機能を実現するにはどうすればよいですか?

私はそれをあまりにも長い間遊んでいて、混乱しています。ヒントをいただければ幸いです。

4

3 に答える 3

15

ビューステートを維持するためにページの初期化でそれらを設定する必要がある動的コントロールを扱っているため、これはトリッキーな状況です。また、ボタンのクリック中に更新パネル内に追加されたコントロールのイベントは、次のポストバックまで登録されないようです。通常のボタンクリックイベントは、新しく追加されたコントロールをクリックするたびに1回だけ発生します。私がやった方法とは別の方法でこれを回避できるかもしれません。誰かが知っているなら私は知りたいです。

私の解決策は、動的に追加したもののリストを保持し、それをセッション変数に格納することです(ページの初期化中にビューステートがロードされないため)。次に、ページのinitで、以前に追加したコントロールをロードします。次に、代わりにカスタムコードまたは通常のクリックイベントを使用して、ページの読み込み中にクリックイベントを処理します。

これをテストするのに役立つサンプルページを作成しました。

aspxページ(default.aspx)のコードは次のとおりです。

<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<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>
    <p>This only updates on full postbacks: <%= DateTime.Now.ToLongTimeString() %></p>
    <asp:UpdatePanel ID="UpdatePanel1" runat="server">
        <ContentTemplate>
            <asp:PlaceHolder ID="PlaceholderControls" runat="server"></asp:PlaceHolder>
        </ContentTemplate>
    </asp:UpdatePanel>
    </form>
</body>
</html>

そして、これがコードビハインドページ(default.aspx.cs)のコードです:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;

public partial class _Default : System.Web.UI.Page
{
    /// <summary>
    /// this is a list for storing the id's of dynamic controls
    /// I have to put this in the session because the viewstate is not
    /// loaded in the page init where we need to use it
    /// </summary>
    public List<string> DynamicControls
    {
        get
        {
            return (List<string>)Session["DynamicControls"];
        }
        set
        {
            Session["DynamicControls"] = value;
        }
    }

    protected void Page_Init(object sender, EventArgs e)
    {
        PlaceholderControls.Controls.Clear();

        //add one button to top that will cause a full postback to test persisting values--
        Button btnFullPostback = new Button();
        btnFullPostback.Text = "Cause Full Postback";
        btnFullPostback.ID = "btnFullPostback";
        PlaceholderControls.Controls.Add(btnFullPostback);

        PlaceholderControls.Controls.Add(new LiteralControl("<br />"));

        PostBackTrigger FullPostbackTrigger = new PostBackTrigger();
        FullPostbackTrigger.ControlID = btnFullPostback.ID;

        UpdatePanel1.Triggers.Add(FullPostbackTrigger);
        //-----------------------------------------------------------------------




        if (!IsPostBack)
        {
            //add the very first control           
            DynamicControls = new List<string>();

            //the DynamicControls list will persist because it is in the session
            //the viewstate is not loaded yet
            DynamicControls.Add(AddControls(NextControl));

        }
        else
        {
            //we have to reload all the previously loaded controls so they
            //will have been added to the page before the viewstate loads
            //so their values will be persisted
            for (int i = 0; i < DynamicControls.Count; i++)
            {
                AddControls(i);
            }
        }


    }

    protected void Page_Load(object sender, EventArgs e)
    {

        if (!IsPostBack)
        {
            //we have to increment the initial
            //control count here here be cause we cannot persit data in the viewstate during 
            //page init

            NextControl++;

        }
        else
        {
            HandleAddNextClick();           

        }

    }

    /// <summary>
    /// this function looks to see if the control which caused the postback was one of our 
    /// dynamically added buttons, we have to do this because the update panel seems to interefere
    /// with the event handler registration.
    /// </summary>
    private void HandleAddNextClick()
    {
        //did any of our dynamic controls cause the postback if so then handle the event
        if (Request.Form.AllKeys.Any(key => DynamicControls.Contains(key)))
        {
            DynamicControls.Add(AddControls(NextControl));
            NextControl++;
        }
    }



    protected void btnAddNext_Command(object sender, CommandEventArgs e)
    {
        //this is intentionally left blank we are handling the click in the page load
        //because the event for controls added dynamically in the click does
        //not get registered until after a postback, so we have to handle it 
        //manually.  I think this has something to do with the update panel, as it works 
        //when not using an update panel, there may be some other workaround I am not aware of

    }

    /// <summary>
    /// variable for holding the number of the next control to be added
    /// </summary>
    public int NextControl
    {
        get
        {
            return  ViewState["NextControl"] == null ? 0 : (int)ViewState["NextControl"];
        }
        set
        {
            ViewState["NextControl"] = value;
        }
    }


    /// <summary>
    /// this function dynamically adds a text box, and a button to the placeholder
    /// it returns the UniqueID of the button, which is later used to find out if the button
    /// triggered a postback
    /// </summary>
    /// <param name="ControlNumber"></param>
    /// <returns></returns>
    private string AddControls(int ControlNumber)
    {
        //add textbox
        TextBox txtValue = new TextBox();
        txtValue.ID = "txtValue" + ControlNumber;
        PlaceholderControls.Controls.Add(txtValue);

        //add button
        Button btnAddNext = new Button();
        btnAddNext.Text = "Add Control " + ControlNumber;
        btnAddNext.ID = "btnAddNext" + ControlNumber;
        int NextControl = ControlNumber + 1;
        btnAddNext.CommandArgument = NextControl.ToString();

        btnAddNext.Command += new CommandEventHandler(btnAddNext_Command);
        PlaceholderControls.Controls.Add(btnAddNext);

        //add a line break
        PlaceholderControls.Controls.Add(new LiteralControl("<br />"));

        return btnAddNext.UniqueID;

    }    
}

このコードが役に立ったかどうか教えてください。何が起こっているのか、どのように機能するのかを理解した上でコメントを追加しようとしました。

于 2010-11-03T14:38:53.770 に答える
0

このように私のために働く

   protected void Page_Load(object sender, EventArgs e)
    {
        if (Page.IsPostBack)
        {
            Button_Click(null, null);
        }
    }

ボタンコールで

 protected void Button_Click(object sender, EventArgs e)
    {
            Panel1.Controls.Clear();
            this.YourMethod();
        }
    }

メソッドを呼び出す前に、コントロールをクリアしてください。そうしないと、2回ロードされます

于 2013-10-29T12:20:26.590 に答える
-1

コントロールのイベントハンドラーを動的にしたい場合は、これを試すことができます-

ボタンコントロールを考えると、

Button btnTest = new Button();
btnTest .Click += new EventHandler(btnTest_Click);

ボタンクリックイベントにコードを含めることができます。

void btnTest_Click(object sender, EventArgs e)
{
    //your code
}
于 2010-11-03T11:31:24.820 に答える