ASP.NET 4.0“模板控制”中的重新绑定事件处理程序?

时间:2017-08-11 03:25:39

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

编辑:可悲的是,似乎没有人知道。也许这有助于澄清我的困境:我正在尝试实现我自己的DataList类型的控件,它支持从ItemTemplate切换到EditItemTemplate。单击EditItemTemplate内的按钮时会出现问题 - 除非您再次单击,否则它不会触发处理程序!

对于冗长的帖子感到抱歉。代码已经完成,但希望没有任何分散注意力。

我正在尝试创建自己的用户控件,接受多个模板。我部分地遵循Manning的“ASP.NET 4.0 in Practice”中的技巧39和40。它似乎正在工作,除了模板内的按钮没有绑定到处理程序,直到第二次单击(在一次额外的回发之后)。

涉及四个文件。 Default.aspx的:

    <%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" %>

    <%@ Register Src="~/TheTemplate.ascx" TagPrefix="TT" TagName="TheTemplate" %>

    <!DOCTYPE html>

    <html xmlns="http://www.w3.org/1999/xhtml">
    <head runat="server">
            <title></title>
    </head>
    <body>
            <form id="form1" runat="server">
                    <div>
                            <TT:TheTemplate ID="tt" runat="server">
                                    <ATemplate>
                                            <p>This is template A</p>
                                            <asp:Button ID="TemplateAButton" OnClick="TemplateAButton_Click" runat="server" Text="Template A Button" />
                                    </ATemplate>
                                    <BTemplate>
                                            <p>This is template B</p>
                                            <asp:Button ID="TemplateBButton" OnClick="TemplateBButton_Click" runat="server" Text="Template B Button" />
                                    </BTemplate>
                            </TT:TheTemplate>
                            <br />
                            <asp:Button ID="ToggleTemplate" Text="Toggle Template" OnClick="ToggleTemplate_Click" runat="server" />
                    </div>
            </form>
    </body>
    </html>

Default.aspx.cs:

    using System;

    public partial class _Default : System.Web.UI.Page
    {
            protected void Page_Load(object sender, EventArgs e)
            {
                    Trace.IsEnabled = true;
                    tt.DataBind();
            }


            protected void ToggleTemplate_Click(object sender, EventArgs e)
            {
                    tt.TemplateName = (tt.TemplateName == "A") ? "B" : "A";
                    tt.DataBind();
            }


            public void TemplateAButton_Click(object sender, EventArgs e)
            {
                    Trace.Write("TemplateAButton_Click");
            }


            public void TemplateBButton_Click(object sender, EventArgs e)
            {
                    Trace.Write("TemplateBButton_Click");
            }
    }

用户控件,TheTemplate.ascx:

    <%@ Control Language="C#" AutoEventWireup="true" CodeFile="TheTemplate.ascx.cs" Inherits="TheTemplate" %>

    <p>Using template <asp:Literal Text="<%# TemplateName %>" ID="Literal1" runat="server"></asp:Literal></p>
    <asp:Placeholder runat="server" ID="PlaceHolder1" />

最后,TheTemplate.ascx.cs:

    using System;
    using System.Web.UI;

    [ParseChildren(true)]
    public class TheTemplateContainer : Control, INamingContainer
    {
            private TheTemplate parent;
            public TheTemplateContainer(TheTemplate parent)
            {
                    this.parent = parent;
            }
    }


    public partial class TheTemplate : System.Web.UI.UserControl, INamingContainer
    {
            public string TemplateName
            {
                    get { return (string)(ViewState["TemplateName"] ?? "A"); }
                    set { ViewState["TemplateName"] = value; }
            }


            [TemplateContainer(typeof(TheTemplateContainer))]
            [PersistenceMode(PersistenceMode.InnerProperty)]
            public ITemplate ATemplate { get; set; }


            [TemplateContainer(typeof(TheTemplateContainer))]
            [PersistenceMode(PersistenceMode.InnerProperty)]
            public ITemplate BTemplate { get; set; }


            protected override void OnDataBinding(EventArgs e)
            {
                    TheTemplateContainer container = new TheTemplateContainer(this);
                    if (TemplateName == "A")
                            ATemplate.InstantiateIn(container);
                    else if (TemplateName == "B")
                            BTemplate.InstantiateIn(container);

                    PlaceHolder1.Controls.Clear();
                    PlaceHolder1.Controls.Add(container);

                    EnsureChildControls();
                    base.OnDataBinding(e);
            }
    }

首次运行时,您会看到正在使用ATemplate:

enter image description here

如果单击“切换模板”按钮,则会正确呈现所有文本:

enter image description here

但是点击“模板A按钮”或“模板B按钮”将不会在第一次尝试时触发OnClick处理程序:

enter image description here

它将在第二次点击时起作用:

enter image description here

问题与调用.DataBind()的位置有关吗?

1 个答案:

答案 0 :(得分:0)

我不太确定我理解它,但问题与新添加的控件如何通过&#34;追赶&#34;事件。删除PlaceHolder1并以编程方式添加它可以解决问题。 TheTemplate.ascx变为:

    <%@ Control Language="C#" AutoEventWireup="true" CodeFile="TheTemplate.ascx.cs" Inherits="TheTemplate" %>

    <p>Using template
            <asp:Literal Text="<%# TemplateName %>" ID="Literal1" runat="server"></asp:Literal></p>

...在TheTemplate.ascx.cs中,像这样替换OnDataBinding:

protected override void OnDataBinding(EventArgs e)
{
    TheTemplateContainer container = new TheTemplateContainer(this);
    if (TemplateName == "A")
        ATemplate.InstantiateIn(container);
    else if (TemplateName == "B")
        BTemplate.InstantiateIn(container);

    System.Web.UI.WebControls.PlaceHolder PlaceHolder1 = new System.Web.UI.WebControls.PlaceHolder();
    //PlaceHolder1.Controls.Clear();
    PlaceHolder1.Controls.Add(container);
    this.Controls.Clear();
    this.Controls.Add(PlaceHolder1);

    EnsureChildControls();
    base.OnDataBinding(e);
}

将来,如果我觉得我需要动态添加控件,我还会动态创建一个PlaceHolder并将其用作root。填充PlaceHolder后,我会将其添加到页面中。