Когда вы создаете ListView, в элементе управления есть свойство, которое позволяет вам указать идентификатор PlaceHolder в LayoutTemplate, который используется для хранения элементов управления для каждого элемента.
<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: Невозможно неявно преобразовать тип 'System.Web.UI.CompiledTemplateBuilder' в 'ControlLibrary.TestTemplate'
<CustomControls:TestContainer ID="testContainer" runat="server">
<TestTemplate>
test
</TestTemplate>
</CustomControls:TestContainer>
Можно ли это сделать или мне нужно будет поместить все настраиваемые свойства в родительский контейнер?
Спасибо за любую помощь, которую вы можете предоставить!
Вы сделали все правильно, кроме объявления свойства шаблона. Любой шаблон должен быть объявлен как System.Web.UI.ITemplate
. Просто замените объявление шаблона:
public ITemplate TestTemplate { get; set; }
И он должен начать работать. Для справки см. Как создать шаблонные пользовательские элементы управления ASP.NET.
Чтобы сделать трюк с настраиваемыми атрибутами для шаблона, вам нужно добавить еще один класс, наследующий из коллекции:
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>
TestTemplate
.