如何在不声明模板标签的情况下对孩子进行控制?

时间:2010-07-12 23:34:19

标签: c# .net asp.net controls controltemplate

我想像Panel一样创建一个控件。

我希望我的控件接受一些控件作为孩子,而不输入模板名称,就像Panel一样,如下所示:

<asp:Panel runat="server">
    My content
    <div>Content</div>
</asp:Panel>

我有内容控件,但没有告诉ITemplate

我基本上想转换这个

<my:MyControl runat="server">
    <ContentTemplate>
        My content
        <div>Content</div>
    </ContentTemplate>
</my:MyControl>

进入这个

<my:MyControl runat="server">
    My content
    <div>Content</div>
</my:MyControl>

这就是我所拥有的:

public class MyControl : CompositeControl
{
    [TemplateInstance(TemplateInstance.Single)]
    public ITemplate Content { get; set; }

    protected override void CreateChildControls()
    {
        base.CreateChildControls();

        Content.InstantiateIn(this);
    }
}

以上内容适用于控件内部的<Content></Content>标记,但没有它不起作用。该属性根本没有做任何事情(我猜)。有什么遗漏?

我怎样才能实现它?任何提示? 为什么Panel支持此功能?

6 个答案:

答案 0 :(得分:7)

我正在从内存中写这个,但我相信答案很简单,就是用属性ParseChildrenAttributePersistChildrenAttribute来装饰你的控件类,你不需要像你提议的那样使用模板

ParseChildrenAttribute.ChildrenAsProperties指定解析器是否应将控件标记的嵌套内容视为属性。将此设置为false将使解析器不会尝试将标记映射到属性名称。

PersistChildrenAttribute将告诉解析器将嵌套内容视为控件,解析后的控件将作为子控件添加到自定义面板控件中。

您的控件的代码将如下所示:

[ParseChildren(false)]
[PersistChildren(true)]
public class MyControl : CompositeControl 
{
    public override void RenderBeginTag(HtmlTextWriter writer)
    {
        base.RenderBeginTag(writer); // TODO: Do something else here if needed
    }     

    public override void RenderEndTag(HtmlTextWriter writer)
    {
        base.RenderEndTag(writer); // TODO: Do something else here if needed
    }
} 

作为参考,您可以启动.NET Reflector并查看Panel控件的实现。

答案 1 :(得分:4)

布鲁诺,你可能正在寻找this。还有一个类似的答案here

答案 2 :(得分:2)

Hey Bruno,答案与用户控件无关,就你想要嵌套控件的方式而言。

它实际上与模板和模板有关。这就是服务器控件如何能够嵌套在其中的特定控件。

这通常是在数据绑定控件中找到

遗憾的是,答案并非微不足道,但您可以找到完整的教程here

更新

嗯......我认为只会让事情复杂化。是什么阻止您创建自定义控件,在其中嵌套控件,然后通过父控件的ControlCollection属性访问这些控件?

答案 3 :(得分:1)

根据您需要执行的操作,您可以创建asp.net Panel控件的子类。

我创建了类似下面的内容来封装我想在每个面板上使用的常用HTML。 (PanelWidth是定义一些标准sizings的枚举。)

public class StyledPanel : System.Web.UI.WebControls.Panel
{
    public PanelWidth PanelWidth { get; set; }

    public override void RenderBeginTag(HtmlTextWriter writer) {            
        string containerClass = string.Format("panel-container-{0}", (int)PanelWidth);
        writer.WriteLine("<div class=\"" + containerClass + "\"" + ">");
    }

    public override void RenderEndTag(HtmlTextWriter writer) {
        writer.WriteLine("</div>");
    }
}

请使用,例如

<uc:StyledPanel PanelWidth="Full" runat="server">
  <div>Stuff</div>
</uc:StyledPanel>

答案 4 :(得分:1)

前两行使其有效:

[ParseChildren(false)]
[PersistChildren(true)]
[ToolboxData("<{0}:MyPanel runat=server>Panel</{0}:MyPanel>")]
public class MyPanel : WebControl
{
}

HTML:

<%@ Register Assembly="WebApplication3" Namespace="WebApplication3" TagPrefix="cc1" %>
<asp:Content ID="HeaderContent" runat="server" ContentPlaceHolderID="HeadContent">
</asp:Content>
<asp:Content ID="BodyContent" runat="server" ContentPlaceHolderID="MainContent">
    <cc1:MyPanel ID="MyPanel1" runat="server">
        <h2>
            Welcome to ASP.NET!
        </h2>
        <p>
            To learn more about ASP.NET visit <a href="http://www.asp.net" title="ASP.NET Website">
                www.asp.net</a>.
        </p>
        <p>
            You can also find <a href="http://go.microsoft.com/fwlink/?LinkID=152368&amp;clcid=0x409"
                title="MSDN ASP.NET Docs">documentation on ASP.NET at MSDN</a>.
        </p>
    </cc1:MyPanel>
</asp:Content>

答案 5 :(得分:0)

构建自定义用户控件,然后利用它来进一步扩展子控件。

http://www.akadia.com/services/dotnet_user_controls.html

    using System;
using System.Collections;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Windows.Forms;
namespace Akadia
{
    namespace SubmitButton
    {
        // User Control which contain a text box for your
        // name and a button that will fire an event.
        public class SubmitButtonControl : System.Windows.Forms.UserControl
        {
            private System.Windows.Forms.TextBox txtName;
            private System.Windows.Forms.Label lblName;
            private System.Windows.Forms.Button btnSubmit;
            private System.ComponentModel.Container components = null;
            // Declare delegate for submit button clicked.
            //
            // Most action events (like the Click event) in Windows Forms
            // use the EventHandler delegate and the EventArgs arguments.
            // We will define our own delegate that does not specify parameters.
            // Mostly, we really don't care what the conditions of the
            // click event for the Submit button were, we just care that
            // the Submit button was clicked.
            public delegate void SubmitClickedHandler();
            // Constructor           public SubmitButtonControl()
            {
                // Create visual controls
                InitializeComponent();
            }
            // Clean up any resources being used.
            protected override void Dispose( bool disposing )
            {
                if( disposing )
                {
                    if( components != null )
                        components.Dispose();
                }
                base.Dispose( disposing );
            }
            .....
            .....
            // Declare the event, which is associated with our
            // delegate SubmitClickedHandler(). Add some attributes
            // for the Visual C# control property.
            [Category("Action")]
            [Description("Fires when the Submit button is clicked.")]
            public event SubmitClickedHandler SubmitClicked;
            // Add a protected method called OnSubmitClicked().
            // You may use this in child classes instead of adding
            // event handlers.
            protected virtual void OnSubmitClicked()
            {
                // If an event has no subscribers registerd, it will
                // evaluate to null. The test checks that the value is not
                // null, ensuring that there are subsribers before
                // calling the event itself.
                if (SubmitClicked != null)
                {
                    SubmitClicked();  // Notify Subscribers
                }
            }
            // Handler for Submit Button. Do some validation before
            // calling the event.
            private void btnSubmit_Click(object sender, System.EventArgs e)
            {
                if (txtName.Text.Length == 0)
                {
                    MessageBox.Show("Please enter your name.");
                }
                else
                {
                    OnSubmitClicked();
                }
            }
            // Read / Write Property for the User Name. This Property
            // will be visible in the containing application.
            [Category("Appearance")]
            [Description("Gets or sets the name in the text box")]
            public string UserName
            {
                get { return txtName.Text; }
                set { txtName.Text = value; }
            }
        }
    }
}