這是一個棘手的情況,因爲您正在處理您需要在頁面init中填充它們的動態控件,以便保持viewstate,控件廣告的事件在點擊按鈕期間更新面板中的代碼似乎不會在下一次回發之前被註冊,因此,每次您單擊新添加的控件時,正常的按鈕單擊事件只會觸發一次。可能還有其他方法可以解決這個問題,而不像我這樣做。如果有人知道我想知道。
我的解決方案是保存動態添加內容的列表,並將其存儲在會話變量中(因爲viewstate在頁面初始化期間未加載)。然後在頁面上加載你以前添加的任何控件。然後在頁面加載過程中使用一些自定義代碼或普通的單擊事件處理單擊事件。
我已經創建了一個示例頁面來幫助測試這個。
下面是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;
}
}
讓我知道這段代碼是否可以幫助你。我試圖用我對正在發生的事情以及工作原理的理解來添加評論。
我一定會檢查你的工作後的解決方案並給你更多的反饋。非常感謝樣品,即使我沒有要求它! – zgorawski 2010-11-03 14:56:34
工程就像一個魅力:)我忘了/不知道你使用的一些功能,所以我的解決方案是不完整的。非常感謝!你幫了我很多:) – zgorawski 2010-11-04 07:27:14
很高興我可以幫忙,我希望有一種方法可以不使用會話,但我不知道任何其他簡單的方法來存儲和檢索視圖狀態加載之前的信息。你大概可以使用隱藏的字段或cookie,但是那些似乎甚至帶有想法。也許有一種方法來手動加載視圖狀態並在頁面init中使用它。 – 2010-11-04 10:57:52