2016-04-25 98 views
0

我希望用户能够通过单击位于该UserControl内的Delete按钮来删除UserControl。UpdatePanel:UserControl内部的按钮没有触发

btnAddChoice工作正常,但btnRemove在UserControl内部,并且btnRemove_Click未被触发。

这里是我的ShowChoices.aspx代码:

<div>     
    <strong>Choices</strong> 
    <asp:UpdatePanel ID="UpdatePanel1" runat="server" ChildrenAsTriggers="true"> 
     <Triggers> 
      <asp:AsyncPostBackTrigger ControlID="btnAddChoice" EventName="Click" />                      
     </Triggers> 
     <ContentTemplate> 
      <ul class="list-unstyled">         
       <asp:PlaceHolder runat="server" ID="phChoices"> 
       </asp:PlaceHolder> 
      </ul> 
     </ContentTemplate> 
    </asp:UpdatePanel>    
</div> 

这里是我的ShowChoices.aspx.cs代码:

protected void btnAddChoice_Click(object sender, EventArgs e) 
{    
    Choice ctl = (Choice)LoadControl("~/Controls/Choice.ascx"); 
    ctl.ID = "choice" + PersistedControls.Count;     
    int j = PersistedControls.Count + 1; 
    ctl.SetSummary("Choice #" + j); 
    phChoices.Controls.Add(ctl); // the UserControl is added here 
    PersistedControls.Add(ctl); 

    AsyncPostBackTrigger trigger = new AsyncPostBackTrigger(); 
    trigger.ControlID = ctl.BtnRemoveUniqueID; // problem : BtnRemoveUniqueID = always null 
    trigger.EventName = "Click"; 
    UpdatePanel1.Triggers.Add(trigger); 
} 

在Choice.ascx:

<asp:Button ID="btnRemove" CssClass="btn-default" runat="server" Text="Remove this choice" CausesValidation="false" OnClick="btnRemove_Click"/> 

在选择.ascx.cs

protected void btnRemove_Click(object sender, EventArgs e) 
{ 
    this.Parent.Controls.Remove(this); 
    List<Control> _persistedControls = (List<Control>) Session[Step2.PersistedControlsSessionKey]; 
    _persistedControls.Remove(this); 
    Session[Step2.PersistedControlsSessionKey] = _persistedControls; 
    UpdatePanel ctl = (UpdatePanel) this.Parent.FindControl("UpdatePanel1"); 
    if (ctl != null) 
    { 
     ctl.Update(); 
    } 
} 

回答

1

用户控件创建一个单独的命名容器,这意味着需要为您更新面板额外的工作(这就是回答在这里做得很好解释它:Trigger an update of the UpdatePanel by a control that is in different ContentPlaceHolder

这是暴露一个按钮的工作的完整示例在用户控件内部,因此它可以充当触发器并触发父页面中的事件。该按钮使用子控件上的公共属性公开,然后所有事件处理程序都附加在父项中。

Default.aspx的

<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" %> 
<%@ Register Src="~/TestChildControl.ascx" TagName="Custom" TagPrefix="TestChildControl" %> 

<!DOCTYPE html> 

<html xmlns="http://www.w3.org/1999/xhtml"> 
<head runat="server"> 
    <title></title> 
</head> 
<body> 
    <form id="form1" runat="server"> 
     <asp:ScriptManager runat="server" /> 
     <div> 
      <asp:UpdatePanel runat="server" ID="updTest"> 
       <Triggers> 
        <asp:AsyncPostBackTrigger ControlID="btnAddControl" EventName="Click" /> 
       </Triggers> 
       <ContentTemplate> 
        <asp:Placeholder runat="server" ID="phControlContainer"></asp:Placeholder> 
       </ContentTemplate> 
      </asp:UpdatePanel> 
      <asp:Button runat="server" ID="btnAddControl" Text="Add Control" OnClick="btnAddControl_OnClick" /> 
     </div> 
    </form> 
</body> 
</html> 

Default.aspx.cs

注意,子控件必须在页面加载在同一顺序用相同的ID,以便为重建事件正常开火。

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Web.UI; 
using System.Web.UI.WebControls; 

public partial class _Default : System.Web.UI.Page 
{ 
    protected void Page_Load(object sender, EventArgs e) 
    { 
     if (ControlIDs != null) 
     { 
      foreach (string controlID in ControlIDs) 
      { 
       AddChildControl(controlID); 
      } 
     } 
    } 

    protected void btnAddControl_OnClick(object sender, EventArgs e) 
    { 
     var rand = new Random(); 
     var controlID = string.Format("TestChildControl_{0}", rand.Next()); 

     AddChildControl(controlID); 
    } 

    protected void AddChildControl(string controlID) 
    { 
     TestChildControl childControl = (TestChildControl)LoadControl("~/TestChildControl.ascx"); 
     childControl.ID = controlID; 
     phControlContainer.Controls.Add(childControl); 

     childControl.RemoveControlButton.Click += btnRemoveControl_OnClick; 

     AsyncPostBackTrigger updateTrigger = new AsyncPostBackTrigger() { ControlID = childControl.RemoveControlButton.UniqueID, EventName = "click" }; 
     updTest.Triggers.Add(updateTrigger); 

     SaveControlIDs(); 
    } 

    private void SaveControlIDs() 
    { 
     ControlIDs = phControlContainer.Controls.Cast<Control>().Select(c => c.ID).ToList(); 
    } 

    protected void btnRemoveControl_OnClick(object sender, EventArgs e) 
    { 
     var removeButton = sender as Button; 

     if (removeButton == null) 
     { 
      return; 
     } 

     var controlID = removeButton.CommandArgument; 
     var parentControl = 
      phControlContainer.Controls.Cast<TestChildControl>().FirstOrDefault(c => c.ID.Equals(controlID)); 

     if (parentControl != null) 
     { 
      phControlContainer.Controls.Remove(parentControl); 
     } 

     SaveControlIDs(); 
    } 

    protected IEnumerable<string> ControlIDs 
    { 
     get 
     { 
      var ids = ViewState["ControlIDs"] ?? new List<string>(); 
      return (IEnumerable<string>) ids; 
     } 
     set { ViewState["ControlIDs"] = value; } 
    } 
} 

TestChildControl.ascx

<%@ Control Language="C#" AutoEventWireup="true" CodeFile="TestChildControl.ascx.cs" Inherits="TestChildControl" %> 
<div> 
    This is a test control 
</div> 
<div> 
    <asp:Button runat="server" ID="btnRemoveControl" Text="Remove Control" /> 
</div> 

TestChildControl.ascx.cs

请注意,在这里我们揭露按钮为只读属性,所以我们可以将事件处理程序它并访问其成员。为方便起见,我将父控件ID分配为CommandArgument。

using System; 
using System.Web.UI.WebControls; 

public partial class TestChildControl : System.Web.UI.UserControl 
{ 
    protected void Page_Load(object sender, EventArgs e) 
    { 
     btnRemoveControl.CommandArgument = this.ID; 
    } 

    public Button RemoveControlButton 
    { 
     get { return btnRemoveControl; } 
    } 
} 
+0

我在使用你的解决方案更新了我的问题,我尝试可惜btnRemove总是空,显然是因为它尚未建立...... –

+0

@JohnMarston我添加了上述的全部工作的例子,说明我已经完成了这一点。 – DVK

相关问题