【问题标题】:How to add a Templating to a UserControl?如何将模板添加到用户控件?
【发布时间】:2012-07-24 09:01:18
【问题描述】:

之前有人问过这个问题

不过再问也无妨:

如何在 ASP.net 中将模板添加到 UserControl

到目前为止没有什么效果

  1. 从一个新的UserControl5 开始,我将其称为Contoso

    public partial class Contoso: System.Web.UI.UserControl
    {
    }
    

    这将允许我们使用新控件:1

    <Contoso>
        Stuff in here
    <Contoso>
    
  2. 创建ITemplate 类型的公共ContentTemplate 属性:

    public partial class Contoso: System.Web.UI.UserControl
    {
       public ITemplate ContentTemplate { get; set; }
    }
    

    并向ContentTemplate 属性添加不确定数量的属性:2

    //[ParseChildren(true)]
    [ParseChildren(true, "ContentTemplate")]
    //[ParseChildren(false)]
    public partial class Contoso: System.Web.UI.UserControl
    {
       [TemplateContainer(typeof(ContentContainer))]
       [TemplateInstance(TemplateInstance.Single)]
       [PersistenceMode(PersistenceMode.InnerProperty)]   
       //[PersistenceMode(PersistenceMode.InnerDefaultProperty)] 
       [Browsable(true)]
       //[Browsable(false)]
       [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
       //[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
       public ITemplate ContentTemplate { get; set; }
    }
    

    这将允许我们将 &lt;ContentTemplate&gt; 添加到我们的 aspx 文件中的控件中:1

    <Contoso>
       <ContentTemplate>
           Stuff in here
       </ContentTemplate>
    </Contoso>
    
  3. 接下来我们需要真正使用 ContentTemplate 的东西,将它添加到某处。为此,我们将其添加到 UserControl 的内部div 元素之一。

    从我们最初为空的.aspx 文件开始:

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

    我们添加一个父 div 来保存我们的 ContentTemplate 东西:

    <%@ Control Language="C#" AutoEventWireup="true" CodeFile="Contoso.aspx.cs" Inherits="Contoso" %>
    <div id="ContentDiv" runat="server"></div>
    

    然后我们在控件的 Init 期间将 ContentTemplate 填充到父 div 中:

    public partial class Contoso: System.Web.UI.UserControl
    {
       protected override void OnInit(EventArgs e)
       {
          base.OnInit(e);
    
          //If there's content, then put it into our ContentDiv div
          if (this.ContentTemplate != null)
             this.ContentTemplate.InstantiateIn(ContentDiv);
       }
    
       [PersistenceModeAttribute(PersistenceMode.InnerProperty)]    
       [TemplateInstanceAttribute(TemplateInstance.Single)]
       [Browsable(true)]
       [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
       public ITemplate ContentTemplate { get; set; }
    }
    
  4. 编辑:表明你的类实现了INamingContainer

    public partial class Contoso: System.Web.UI.UserControl: INamingContainer
    {
       protected override void OnInit(EventArgs e)
       {
          base.OnInit(e);
    
          //If there's content, then put it into our ContentDiv div
          if (this.ContentTemplate != null)
             this.ContentTemplate.InstantiateIn(ContentDiv);
       }
    
       [PersistenceModeAttribute(PersistenceMode.InnerProperty)]    
       [TemplateInstanceAttribute(TemplateInstance.Single)]
       [Browsable(true)]
       [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
       public ITemplate ContentTemplate { get; set; }
    }
    

    INamingContainer 接口没有任何成员,仅用于将您的UserControl 类标记为某事。

  5. 我们完成了3。我们现在可以在我们的 aspx 页面中使用这个控件。但首先我们需要在我们的 aspx 页面顶部“注册”它:

    <%@ Register src="Contoso.ascx" TagName="Contoso" tagprefix="uc" %>
    

    地点:

    • Contoso.ascxascx 文件的名称
    • Contoso 是我们将用来引用此用户控件的元素的名称
    • uc 是我们必须放在uc:Contoso 前面的一段文字(我使用uc 作为user-control 的缩写)
  6. 将控件添加到我们的页面:

    <uc:Contoso ID="Crackers" runat="server">
        <ContentTemplate>
            Stuff goes here
        </ContentTemplate>
    </qwerty:Contoso>
    

我们完成了!4

编辑:忘记添加上述不起作用的原因。 Visual Studio 显示错误:

创建控件时出错 - 破解器

类型“System.Web.UI.UserControl”没有名为“ContentTemplate”的公共属性

这是有道理的,因为 UserControl 没有名为 ContentTemplate 的公共属性 - 所以我很难责怪它。

系列

这个问题是 Stackoverflow 系列中的一个,“模板化用户控件”

阅读奖励

脚注

  • 1 你永远不能使用那种语法。这只是一种易于阅读和理解的形式。
  • 2 没有人知道要添加什么属性,或者为什么。为口味添加或多或少的属性。
  • 3 未完成。完成了 UserControl,但不是我们的工作。
  • 4 未完成;它不起作用。
  • 5 在网站中(不是 Web 应用程序,不是在单独的程序集中)

【问题讨论】:

  • 如果您将脚注内嵌在文本中会更容易阅读,向下滚动只是为了阅读注释很烦人
  • @Jupaol 脚注没有添加任何与问题相关的内容,只是为了防止那些想要挑剔不重要细节的挑剔者。用这种无关紧要的废话乱扔问题是一种耻辱。

标签: asp.net user-controls templating webusercontrol


【解决方案1】:

嗯,我相信你几乎明白了。

顺便说一句。 UserControl 不是使用 Visual Studio 设计器呈现的,但是当您运行应用程序时,该控件可以工作。如果您改用服务器控件,情况会有所不同,在这种情况下,控件会正确显示在 Visual Studio 设计器中

以下代码非常适合构建模板化用户控件和模板化服务器控件,但是,如果您想添加绑定功能,则过程略有不同,take a look

Download Source Code

这是创建模板化UserControl 的代码。

简单输出

模板容器

public class MyTemplateContainer : Control, INamingContainer { }

ASPX 代码背后

protected void Page_Load(object sender, EventArgs e)
{
    // just to demonstrate using the contorl
    this.WebUserControl1.Controls.Add(new LiteralControl("<br />new control"));
}

ASPX

<%@ Register src="WebUserControl.ascx" tagname="WebUserControl" tagprefix="uc1" %>

    <uc1:WebUserControl ID="WebUserControl1" runat="server">
        <ContentTemplate>
            My Template<br />
            <asp:Label Text='Hello People' runat="server" ID="lblMessage" />
        </ContentTemplate>
    </uc1:WebUserControl>

ASCX 代码背后

public partial class WebUserControl : System.Web.UI.UserControl
{
    [TemplateContainer(typeof(MyTemplateContainer))]
    [TemplateInstance(TemplateInstance.Single)]
    [PersistenceMode(PersistenceMode.InnerProperty)]
    [Browsable(true)]
    [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
    public ITemplate ContentTemplate { get; set; }

    protected void Page_Init(object sender, EventArgs e)
    {
        this.myPlaceHolderTag.Controls.Clear();

        if (this.ContentTemplate != null)
        {
            var container = new MyTemplateContainer();

            this.ContentTemplate.InstantiateIn(container);
            this.myPlaceHolderTag.Controls.Add(container);
        }
        else
        {
            this.myPlaceHolderTag.Controls.Add(new LiteralControl("No template defined"));
        }
    }
}

ASCX

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

<asp:PlaceHolder runat="server" ID="myPlaceHolderTag" />

添加模板化服务器控件的代码

输出

ASPX

<%@ Register Namespace="MyControls" TagPrefix="my" %>

<my:MyServerControl runat="server" ID="myServerControl">
    <ContentTemplate>
        My Server templated control<br />
        <asp:Label Text="My Label" runat="server" />
    </ContentTemplate>
</my:MyServerControl>

模板容器

namespace MyControls
{
    [ToolboxItem(false)]
    public class MyTemplateContainer : Control, INamingContainer { } 
}

模板化服务器控制

namespace MyControls
{
    [ToolboxData("<{0}:MyServerControl runat=server >")]
    [ToolboxItem(true)]
    [ParseChildren(true)]
    // you can inherit from another control if you like, for example from the CompositeControl
    public class MyServerControl : Control, INamingContainer
    {
        [TemplateInstance(TemplateInstance.Multiple)]
        [TemplateContainer(typeof(MyTemplateContainer))]
        [PersistenceMode(PersistenceMode.InnerProperty)]
        [Browsable(true)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
        [DefaultValue(null)]
        public ITemplate ContentTemplate { get; set; }

        protected override void CreateChildControls()
        {
            var p = new Panel { ID = "myPanel", BackColor = Color.Silver, Width = new Unit("100%") };

            if (this.ContentTemplate == null)
            {
                p.Controls.Add(new LiteralControl("No content has been specified"));
            }
            else
            {
                var c = new MyTemplateContainer();

                this.ContentTemplate.InstantiateIn(c);
                p.Controls.Add(c);
            }

            this.Controls.Clear();
            this.Controls.Add(p);
        }

        public override void DataBind()
        {
            this.CreateChildControls();
            this.ChildControlsCreated = true;
            base.DataBind();
        }

        public override ControlCollection Controls
        {
            get
            {
                this.EnsureChildControls();
                return base.Controls;
            }
        }
    }
}

参考资料:

【讨论】:

  • @IanBoyd - 当我测试它时,它对我来说效果很好。你有机会测试 Jupaol 的答案吗?
  • @peter 我实际上没有机会测试它;因为我这周正在度假(远离包含错误控件的有问题的 Visual Studio 2010 ASP.net 网站)。我肯定会很快对其进行测试;因为在设计时不再能够查看任何页面是一个真正的障碍。
  • @peter 不幸的是,我不能说这解决了 Visual Studio 无法呈现包含 ContentTemplate 的页面的问题,直到我解决了 Visual Studio 无法呈现页面的单独问题包含ContentTemplate。不同的是,一个是我的自己的UserControl,另一个是微软的 UpdatePanel。虽然此处的解决方案(停止使用UserControls)可能有效,但我无法更新Microsoft Ajax Toolkit 来告诉他们 停止使用UserControls。所以我被我无法编辑的页面困住了。
  • 一年过去了,我想看看问题是否得到了解决。我正在阅读我最初的问题,其中包含很多 WebForms 废话:添加永无止境的属性,必须从某些类继承,必须调用方法。这让我想知道当我决定使用 WebForms 时我在想什么;我应该使用 MVC。
猜你喜欢
  • 2012-04-03
  • 2011-10-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多