2010-11-03 100 views
5

我想创建一个控件,允许用户设计自己的网站结构。我想到UpdatePanel内部是TextBox(页面名称)和Button'加在下面'的控件。它会看起来像:在UpdatePanel中动态创建控件?

| "Questions" | 
| [ add below ] | 

|  "Tags" | 
| [ add below ] | 

| "Badges" | 
| [ add below ] | 
现在

时,在“标签”元素按钮,用户点击,应该出现新的“标签”和“徽章”之间,可编辑的名称,以便用户可以将其命名为“用户”例如。它应该没有完整的回发完成(以避免页面闪烁)。

现在是我的问题:我不能在onInit中加载这些控件(最后不是所有的控件),因为它们不存在,但我必须关注它们的click事件,所以我应该附加事件监听器在Init过程中应该做什么相。 如何实现所描述的功能?

我在周围玩了太久,我很困惑。我会很感激任何提示。

回答

12

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

    }  
} 

让我知道这段代码是否可以帮助你。我试图用我对正在发生的事情以及工作原理的理解来添加评论。

+0

我一定会检查你的工作后的解决方案并给你更多的反馈。非常感谢样品,即使我没有要求它! – zgorawski 2010-11-03 14:56:34

+0

工程就像一个魅力:)我忘了/不知道你使用的一些功能,所以我的解决方案是不完整的。非常感谢!你帮了我很多:) – zgorawski 2010-11-04 07:27:14

+0

很高兴我可以帮忙,我希望有一种方法可以不使用会话,但我不知道任何其他简单的方法来存储和检索视图状态加载之前的信息。你大概可以使用隐藏的字段或cookie,但是那些似乎甚至带有想法。也许有一种方法来手动加载视图状态并在页面init中使用它。 – 2010-11-04 10:57:52

-1

如果你想为你的控件的动态事件处理,那么你可以试试这个 -

考虑一个按钮控制,

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

您可以在按钮单击事件代码,

void btnTest_Click(object sender, EventArgs e) 
{ 
    //your code 
} 
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(); 
     } 
    } 

之前调用该方法,否则清除控制它会加载两次