这是一个棘手的情况,因为您正在处理您需要在页面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