【问题标题】:UpdatePanel : Button inside UserControl not firingUpdatePanel:UserControl 内的按钮未触发
【发布时间】:2016-04-25 20:15:18
【问题描述】:

我希望用户能够通过单击位于用户控件内的删除按钮来删除用户控件。

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();
    }
}

【问题讨论】:

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


    【解决方案1】:

    用户控件创建一个单独的命名容器,这意味着您的更新面板需要额外的工作(这里的 SO 答案很好地解释了它: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; }
        }
    }
    

    【讨论】:

    • 我已经通过尝试使用您的解决方案更新了我的问题,但不幸的是 btnRemove 始终为空,显然是因为它尚未创建...
    • @JohnMarston 我在上面添加了一个完整的工作示例,说明我是如何完成这项工作的。
    猜你喜欢
    • 2016-05-23
    • 1970-01-01
    • 2017-02-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多