2010-11-03 45 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(); 
     } 
    } 

之前調用該方法,否則清除控制它會加載兩次