UpdatePanel:UserControl内的按钮未触发

时间:2016-04-25 20:15:19

标签: c# asp.net user-controls asp.net-ajax

我希望用户能够通过单击UserControl内的“删除”按钮来删除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"/>

在Choice.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 个答案:

答案 0 :(得分: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; }
    }
}