无法将类型'System.Web.UI.CompiledTemplateBuilder'隐式转换为自定义ITemplate

时间:2014-08-24 21:50:26

标签: c# asp.net webforms custom-controls

创建ListView时,控件上有一个属性,允许您在LayoutTemplate中指定PlaceHolder的ID,用于保存每个项目的控件。

<asp:ListView ID="lvTest" runat="server" ItemPlaceholderID="testPlaceholder">
    <LayoutTemplate>
        <ul>
            <asp:PlaceHolder ID="testPlaceholder" runat="server" />
        </ul>
    </LayoutTemplate>
    <ItemTemplate>
        <li>Item</li>
    </ItemTemplate>
</asp:ListView>

我正在尝试创建一个自定义的模板化服务器控件,但希望在模板本身上有一个属性,因为我希望有几个不同的模板。我非常简单,琐碎的例子如下:

using System;
using System.Web.UI;
using System.Web.UI.WebControls;

namespace ControlLibrary
{
    [ParseChildren(true)]
    public class TestContainer : Control, INamingContainer
    {
        [PersistenceMode(PersistenceMode.InnerProperty)]
        [TemplateContainer(typeof(TestContainer))]
        public TestTemplate TestTemplate { get; set; }

        protected override void OnLoad(EventArgs e)
        {
            base.OnLoad(e);

            DataBind();
        }

        public override void DataBind()
        {
            base.DataBind();

            CreateChildControls();
        }

        protected override void CreateChildControls()
        {
            Controls.Clear();

            var phTest = new PlaceHolder();
            phTest.ID = "phTest";

            Controls.Add(phTest);

            if (this.TestTemplate != null)
                this.TestTemplate.InstantiateIn(phTest);

            this.ChildControlsCreated = true;
        }
    }

    public class TestTemplate : ITemplate
    {
        public string Name { get; set; }

        public void InstantiateIn(Control container)
        {
            container.Controls.Add(new LiteralControl(this.Name));
        }
    }
}

但是,如果我将模板添加到我的.aspx文件中,如下所示,我收到一条错误消息 CS0029:无法隐式转换类型&#39; System.Web.UI.CompiledTemplateBuilder&#39;到&#39; ControlLibrary.TestTemplate&#39;

<CustomControls:TestContainer ID="testContainer" runat="server">
    <TestTemplate>
        test
    </TestTemplate>
</CustomControls:TestContainer>

是否可以这样做或者我必须将所有可配置属性放在父容器本身上?

感谢您提供的任何帮助!

1 个答案:

答案 0 :(得分:2)

除模板属性声明外,您已正确完成所有操作。任何模板都必须声明为System.Web.UI.ITemplate。只需将模板声明替换为:

public ITemplate TestTemplate { get; set; }

它应该开始工作了。有关参考,请参阅How to: Create Templated ASP.NET User Controls

要使用模板的自定义属性进行操作,您需要再添加一个继承自集合的类:

public class TestTemplateList : List<TestTemplate> { }

并将控件的声明更改为:

[ParseChildren(true, DefaultProperty = "TestTemplates")]
public class TestContainer : Control, INamingContainer
{
    [PersistenceMode(PersistenceMode.InnerProperty)]
    public TestTemplateList TestTemplates { get; set; }

    // ... OnLoad and DataBind left intact

    protected override void CreateChildControls()
    {
        Controls.Clear();

        var phTest = new PlaceHolder();
        phTest.ID = "phTest";

        Controls.Add(phTest);

        if (this.TestTemplates != null)
        {
            foreach (var testTemplate in TestTemplates)
            {
                ((ITemplate)testTemplate).InstantiateIn(phTest);    
            }
        }

        this.ChildControlsCreated = true;
    }
}

之后你应该能够以两种方式宣布控制。您可以跳过指定TestTemplates,因为它在DefaulProperty中被声明为ParseChildrenAttribute

<CustomControls:TestContainer runat="server" ID="testContainer">
    <CustomControls:TestTemplate Name="test">
    </CustomControls:TestTemplate>
</CustomControls:TestContainer>

<%-- OR --%>

<CustomControls:TestContainer runat="server" ID="wc11">
    <TestTemplates>
        <CustomControls:TestTemplate Name="test">
        </CustomControls:TestTemplate>
    </TestTemplates>
</CustomControls:TestContainer>