我想创建控件,允许用户设计自己的网站结构.我想在UpdatePanel里面是带有TextBox(用于页面名称)和Button“add below”的控件.它看起来像:
| "Questions" | | [ add below ] | | "Tags" | | [ add below ] | | "Badges" | | [ add below ] |
现在当用户点击“标签”元素中的按钮时,应该在“标签”和“徽章”之间出现新的,具有可编辑的名称,因此用户可以将其命名为“用户”.它应该在没有完全回发的情况下完成(以避免页面闪烁).
现在是我的问题:我无法加载onInit中的那些控件(最后不是全部)因为它们不存在,但我必须关注它们的click事件,所以我应该附加事件监听器在Init阶段应该做什么.如何实现所描述的功能?
我玩了太多时间,我很困惑.我会很感激任何提示.
解决方法
这是一个棘手的情况,因为你正在处理你需要在页面init上填充它们以保持viewstate的动态控件,在按钮点击期间添加到更新面板内的控件的事件似乎在下一次回发之前都没有注册,所以正常的按钮单击事件仅在您每次点击新添加的控件时触发一次.除了我的方式之外,可能还有其他一些方法可以解决这个问题.如果有人知道我想知道.
我的解决方案是保留动态添加的列表,并将其存储在会话变量中(因为在初始化期间未加载视图状态).然后在页面上初始化加载您之前添加的任何控件.然后在页面加载期间使用一些自定义代码或正常单击事件处理click事件.
我创建了一个示例页面来帮助测试它.
<%@ 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; } }