使用 DataBinding 创建自定义控件
Create custom control with DataBinding
我创建了一个 SearchResults
控件来显示搜索结果。此控件有一个重复元素(显示结果),但也包含我为这个问题删除的其他元素。
当前在以下示例中 DataItem
无法解析。我正在尝试弄清楚如何使 DataItem
可解析,以便我可以按以下方式使用此控件:
<Controls:SearchResults runat="server" id="Results">
<RowHeaderTemplate>
<tr>
<td>User ID</td>
</tr>
</RowHeaderTemplate>
<RowItemTemplate>
<tr>
<td>
<%#((Models.User)Container.DataItem).ID %>
</td>
</tr>
</RowItemTemplate>
</Controls:SearchResults>
是这样使用的:
var searchResults = GetSearchResults();
Results.DataSource = searchResults ;
Results.DataBind();
搜索结果控制代码:
[System.ComponentModel.DefaultBindingProperty("DataSource")]
public partial class Search : UserControl
{
[PersistenceMode(PersistenceMode.InnerProperty), TemplateContainer(typeof(TemplateControl))]
public ITemplate RowHeaderTemplate { get; set; }
[PersistenceMode(PersistenceMode.InnerProperty), TemplateContainer(typeof(TemplateControl))]
public ITemplate RowItemTemplate { get; set; }
public IEnumerable<object> DataSource { private get; set; }
private bool DataBindingComplete { get; set; }
public override void DataBind()
{
if (DataBindingComplete) return;
foreach (var obj in DataSource)
{
var newControl = new PlaceHolder();
RowItemTemplate.InstantiateIn(newControl);
RowItemContainer.Controls.Add(newControl);
}
DataBindingComplete = true;
base.DataBind();
}
protected void Page_Load(object sender, EventArgs e)
{
if (!Visible) return;
OnInit(e);
if (RowHeaderTemplate != null)
{
RowHeaderTemplate.InstantiateIn(RowHead);
}
}
}
带有标记:
<asp:PlaceHolder runat="server" ID="Wrapper">
<h2>Results</h2>
<table border="1">
<asp:PlaceHolder runat="server" ID="RowHead"/>
<asp:Placeholder runat="server" Visible='<%#TotalResults == 0 %>'>
<tr>
<td colspan="100">
No results returned!
</td>
</tr>
</asp:Placeholder>
<asp:Placeholder runat="server" ID="RowItemContainer" Visible='<%#TotalResults > 0 %>'>
</asp:PlaceHolder>
</table>
</asp:PlaceHolder>
请注意这是一个精简的示例,仅使用 Repeater
控件代替它是不够的。
问题是搜索控件的 RowItemTemplate 属性 的 TemplateContainer 属性引用了没有 DataItem 属性 的 TemplateControl。不使用 TemplateControl,而是创建一个具有 DataItem 属性:
的 SearchItem 控件
public class SearchItem : Control, INamingContainer
{
public object DataItem { get; set; }
}
在搜索 class 中,更改 RowItemTemplate 属性 的 TemplateContainer 属性,使其引用 SearchItem 而不是 TemplateControl:
[PersistenceMode(PersistenceMode.InnerProperty), TemplateContainer(typeof(SearchItem))]
public ITemplate RowItemTemplate { get; set; }
此外,实例化 SearchItem 而不是 DataBind 中的 PlaceHolder:
var newControl = new SearchItem { DataItem = obj };
这些是让您的示例正常工作所需的最少更改。但是,您的自定义控件不会自动跨回发保留项目。要实现该功能,我建议您研究 Repeater class.
的源代码
我创建了一个 SearchResults
控件来显示搜索结果。此控件有一个重复元素(显示结果),但也包含我为这个问题删除的其他元素。
当前在以下示例中 DataItem
无法解析。我正在尝试弄清楚如何使 DataItem
可解析,以便我可以按以下方式使用此控件:
<Controls:SearchResults runat="server" id="Results">
<RowHeaderTemplate>
<tr>
<td>User ID</td>
</tr>
</RowHeaderTemplate>
<RowItemTemplate>
<tr>
<td>
<%#((Models.User)Container.DataItem).ID %>
</td>
</tr>
</RowItemTemplate>
</Controls:SearchResults>
是这样使用的:
var searchResults = GetSearchResults();
Results.DataSource = searchResults ;
Results.DataBind();
搜索结果控制代码:
[System.ComponentModel.DefaultBindingProperty("DataSource")]
public partial class Search : UserControl
{
[PersistenceMode(PersistenceMode.InnerProperty), TemplateContainer(typeof(TemplateControl))]
public ITemplate RowHeaderTemplate { get; set; }
[PersistenceMode(PersistenceMode.InnerProperty), TemplateContainer(typeof(TemplateControl))]
public ITemplate RowItemTemplate { get; set; }
public IEnumerable<object> DataSource { private get; set; }
private bool DataBindingComplete { get; set; }
public override void DataBind()
{
if (DataBindingComplete) return;
foreach (var obj in DataSource)
{
var newControl = new PlaceHolder();
RowItemTemplate.InstantiateIn(newControl);
RowItemContainer.Controls.Add(newControl);
}
DataBindingComplete = true;
base.DataBind();
}
protected void Page_Load(object sender, EventArgs e)
{
if (!Visible) return;
OnInit(e);
if (RowHeaderTemplate != null)
{
RowHeaderTemplate.InstantiateIn(RowHead);
}
}
}
带有标记:
<asp:PlaceHolder runat="server" ID="Wrapper">
<h2>Results</h2>
<table border="1">
<asp:PlaceHolder runat="server" ID="RowHead"/>
<asp:Placeholder runat="server" Visible='<%#TotalResults == 0 %>'>
<tr>
<td colspan="100">
No results returned!
</td>
</tr>
</asp:Placeholder>
<asp:Placeholder runat="server" ID="RowItemContainer" Visible='<%#TotalResults > 0 %>'>
</asp:PlaceHolder>
</table>
</asp:PlaceHolder>
请注意这是一个精简的示例,仅使用 Repeater
控件代替它是不够的。
问题是搜索控件的 RowItemTemplate 属性 的 TemplateContainer 属性引用了没有 DataItem 属性 的 TemplateControl。不使用 TemplateControl,而是创建一个具有 DataItem 属性:
的 SearchItem 控件public class SearchItem : Control, INamingContainer
{
public object DataItem { get; set; }
}
在搜索 class 中,更改 RowItemTemplate 属性 的 TemplateContainer 属性,使其引用 SearchItem 而不是 TemplateControl:
[PersistenceMode(PersistenceMode.InnerProperty), TemplateContainer(typeof(SearchItem))]
public ITemplate RowItemTemplate { get; set; }
此外,实例化 SearchItem 而不是 DataBind 中的 PlaceHolder:
var newControl = new SearchItem { DataItem = obj };
这些是让您的示例正常工作所需的最少更改。但是,您的自定义控件不会自动跨回发保留项目。要实现该功能,我建议您研究 Repeater class.
的源代码