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