65.9K
CodeProject 正在变化。 阅读更多。
Home

创建带模板的用户控件

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.77/5 (23投票s)

2007 年 12 月 1 日

CPOL

4分钟阅读

viewsIcon

125700

downloadIcon

1831

本文将介绍如何创建自己的、带有模板的 Repeater 控件。

引言

现代 Web 编程技术 ASP.NET 提供了许多工具和控件,可以快速开发 Web 应用程序。例如,Repeater 控件是一个非常简单且强大的控件,可以在短时间内将集合数据渲染到网页中。想象一下,如果您在经典 ASP 或 PHP 中要做同样的事情,您可能需要在 ASP 中编写一个包含 HTML 和服务器脚本的循环。ASP 和 ASP.NET 的第一个区别是 HTML 和服务器脚本的分离。微软提供了许多控件供您使用,例如:RepeaterDataGridViewDataList 等。在本文中,我将介绍如何创建这种模板化数据控件。

选择合适的场景

每次都创建自定义控件都是一种时间上的消耗。此外,它可能无法在所有场景下得到妥善的测试。选择像 DataReader 这样由微软本身提供和测试的控件,始终是最佳方法。然而,在某些场景下,我们可能需要更好的功能和控件定制。在这种情况下,我们会选择 UserControl [或] CustomControl 开发。

在本文中,我将介绍一个典型的 DataRepeater 开发。即使 ASP.NET 中已经提供了这个控件,我们仍然要创建一个类似 Repeater 的控件(Repeating Repeater),因为我们已经熟悉 Repeater 控件的功能及其模板,所以很容易理解。

规划控件

由于我们将创建一个类似 DataRepeater 的控件,所以关于控件的规划也很容易。我将只更改控件的名称。控件的名称是 MyRepeater,它包含以下四个模板:

  • Header 模板
  • Footer 模板
  • Item 模板
  • Alternate item 模板

我们已经知道,Header 和 Footer 应该只渲染一次,而 Item 模板和 AlternateItemTemplate 的数量应该等于 DataSource 中项目的数量。

规划 DataSource

Repeater 一样,我们的控件也应该支持大多数通用类型,如下所示:

  • DataTable
  • 数据视图
  • 列表
  • Collection
  • ArrayList
  • 数组

不要纠结于如何在控件内部处理所有上述数据类型。这真的很简单。所有上述数据类型都内部实现了 IEnumerable,所以如果我们为 IEnumerable 开发一个控件,它将支持所有上述数据源。

重要数据类型

我们将使用以下重要数据类型来开发我们自己的 Repeater,请参阅 MSDN 以获取这些类型的详细描述:

  • ITemplate
  • IEnumerable
  • INamingContainer
  • IDataItem
  • Control

创建用户控件

创建一个名为 MyRepeater.ascx 的新用户控件,并在 Default.aspx 中引用它。因此,default.aspxMyRepeater.ascx 将如下所示:

MyRepeater.ascx

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

Default.aspx

<%@ Page Language="C#" AutoEventWireup="true"
    CodeFile="Default.aspx.cs" Inherits="_Default" %>

<%@ Register Src="MyRepeater.ascx" TagName="MyRepeater" TagPrefix="myOwn" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
    <title>Untitled Page</title>

</head>
<body>
    <form id="form1" runat="server">
    <div>
        <myOwn:MyRepeater ID="MyRepeater1" runat="server">
        </myOwn:MyRepeater>

    </div>
    </form>
</body>
</html>

创建模板

默认情况下,UserControl 内部没有任何模板,所以我们必须创建 public 属性来启用 UserControl 的模板。在 UserControl 内部创建以下四个 public 属性:

MyRepeater.ascx.cs

using System;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.HtmlControls;
using System.Collections;
public partial class MyRepeater : System.Web.UI.UserControl
{
    private ITemplate _ItemTemplate;
    private ITemplate _AlternateItemTemplate;
    private ITemplate _HeaderTemplate;
    private ITemplate _FooterTemplate;
    private IEnumerable _DataSource;

    protected void Page_Load(object sender, EventArgs e)
    {

    }

    [TemplateContainer(typeof(SimpleTemplateItem))]
    public ITemplate ItemTemplate
    {
        get { return _ItemTemplate; }
        set { _ItemTemplate = value; }
    }

    [TemplateContainer(typeof(SimpleTemplateItem))]
    public ITemplate AlternateItemTemplate
    {
        get { return _AlternateItemTemplate; }
        set { _AlternateItemTemplate = value; }
    }

    [TemplateContainer(typeof(SimpleTemplateItem))]
    public ITemplate HeaderTemplate
    {
        get { return _HeaderTemplate; }
        set { _HeaderTemplate = value; }
    }

    [TemplateContainer(typeof(SimpleTemplateItem))]
    public ITemplate FooterTemplate
    {
        get { return _FooterTemplate; }
        set { _FooterTemplate = value; }
    }
 }
  • ITemplate:这是 ASP.NET 提供的接口,用于保存特定的模板内容。
  • TemplateContainer:此属性用于提供模板内容的类型。

对于每个模板,运行时都必须创建一个 UserControl 实例来保存内容。例如,如果您的 DataSource 有 100 条记录,则内部将创建 100 个模板实例。我们需要创建另一个 UserControl 来将每个模板渲染到其中。这个控件称为模板容器控件。创建类/控件如下:

SimpleTemplateItem.cs

public class SimpleTemplateItem :
    Control, System.Web.UI.INamingContainer, IDataItemContainer
{
    private object _CurrentDataItem;
    public SimpleTemplateItem(object currentItem)
    {
        _CurrentDataItem = currentItem;

    }

    #region IDataItemContainer Members

    public object DataItem
    {
        get { return _CurrentDataItem; }
    }

    public int DataItemIndex
    {
        get { throw new Exception
            ("The method or operation is not implemented."); }
    }

    public int DisplayIndex
    {
        get { throw new Exception
            ("The method or operation is not implemented."); }
    }

    #endregion
}
  • INamingContainer:这是一个 Marker 接口 — 它没有任何方法或属性 — 它只是为了在运行时提供控件 ID。
  • IDataItemIDataItem 的属性用于相对于模板实例保存 DataSource 的单个项目。

添加代码以渲染模板

到目前为止,我们已经创建了一个具有四个模板属性的 UserControl,以及另一个 UserControl(模板容器)来在其上渲染模板。现在我们需要添加代码逻辑来渲染模板。ITemplate 接口内部有一个名为 InstantiateIn 的方法,用于将模板内容渲染到所需的控件中。将以下代码添加到 myrepeater 类的 databind 方法中,这将把模板添加到 UserControl 中。

MyRepeater.ascx.cs [Databind 方法]

 public override void DataBind()
    {
        //Rendering Header template into current control

        AddTemplateAsControl(HeaderTemplate, null);

        IEnumerator ie = DataSource.GetEnumerator();
        bool renderAlternateTemplate = false;

        while (ie.MoveNext())
        {


            if (renderAlternateTemplate && AlternateItemTemplate != null)
            {

                AddTemplateAsControl(ItemTemplate, ie.Current);
            }
            else if (AlternateItemTemplate != null)
            {
                AddTemplateAsControl(AlternateItemTemplate,ie.Current);
            }
            else
            {
                //don't render anything

            }

            renderAlternateTemplate = !renderAlternateTemplate;
        }

        //Rendering footer template into current control

        AddTemplateAsControl(FooterTemplate, null);

        //Always better to call base class implementation

        base.DataBind();
    }
    
    private void AddTemplateAsControl(ITemplate anyTemplate,object cuurentItem)
    {
        SimpleTemplateItem templateContentHolder = new SimpleTemplateItem(cuurentItem);
        anyTemplate.InstantiateIn(templateContentHolder);
        this.Controls.Add(templateContentHolder);
    }
    

测试 MyRepeater

要测试 Repeater,请创建任何 DataSource 并将其绑定到 UserControl。下面是测试 Repeater 的示例代码。

Default.aspx

<myOwn:MyRepeater ID="MyRepeater1" runat="server">

        <HeaderTemplate>
            Customer List:
            <table border="1">
                <tr><th>Id</th><th>Name</th><th>Location</th></tr>

        </HeaderTemplate>

        <ItemTemplate>
            <tr style="background-color:gold">
            <td><%#DataBinder.Eval(Container.DataItem,"Id") %></td>
            <td><%#DataBinder.Eval(Container.DataItem,"Name")%></td>

            <td><%#DataBinder.Eval(Container.DataItem,"Location") %></td>
            </tr>
        </ItemTemplate>

        <AlternateItemTemplate>
            <tr><td><%#DataBinder.Eval(Container.DataItem,"Id") %></td>

            <td><%#DataBinder.Eval(Container.DataItem,"Name")%></td>
            <td><%#DataBinder.Eval(Container.DataItem,"Location") %></td>
            </tr>
        </AlternateItemTemplate>

        <FooterTemplate>
            </table>
            </FooterTemplate>

    </myOwn:MyRepeater>

Default.aspx.cs

using System;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.HtmlControls;
using System.Collections.Generic;

public partial class _Default : System.Web.UI.Page
{
    protected void Page_Load(object sender, EventArgs e)
    {
        List<Customer> customerList = new List<Customer>();

        customerList.Add(new Customer("Prem", "New york"));
        customerList.Add(new Customer("Jhon", "Amsterdam"));
        customerList.Add(new Customer("Peter", "London"));
        customerList.Add(new Customer("Mani", "Chennai"));
        customerList.Add(new Customer("Paul", "Paris"));

        MyRepeater1.DataSource = customerList;
        MyRepeater1.DataBind();
    }
}

public class Customer
{
    private string _Name;
    private Guid _Id;
    private string _Location;

    public Customer(string name, string location)
    {
        this.Name = name;
        this.Location = location;
        this.Id = Guid.NewGuid();
    }

    public string Name
    {
        get { return _Name; }
        set { _Name = value; }
    }

    public Guid Id
    {
        get { return _Id; }
        set { _Id = value; }
    }

    public string Location
    {
        get { return _Location; }
        set { _Location = value; }
    }
}

结论

我希望您已理解如何开发自己的模板化控件,例如 DataGridDataList 等,并添加自己的功能。如果不需要任何额外的功能,也可以使用现有的 RepeaterItem 类,而不是 SimpleTemplateItem 类。我们创建的控件非常轻量级,就像普通的 Repeater 一样。如果需要,您还可以添加一些额外的功能,如分页、排序等。

© . All rights reserved.