公司最近的一个项目需要涉及到动态订单,即每位用户订单数据表的属性列是可以自定义的,数据表字段是动态的,所以使用GridView等控件对未知数据表进行操作时,需要使用动态模板。实现如下:                          


为GridView控件创建自定义模板

当使用模板控件时,可能直到运行时还不了解所需要的模板,或者模板中应该包括的文本或者控件。在这种情况下,可以在代码中动态创建模板。可以在代码中为所有使用模板的控件创建模板:DataList、Repeater、GridView、FormView、DetailsView等。对于GridView控件而言,使用模板可定义列,而不是其他控件那样的行布局模板。下面实例将介绍使用GridView控件自定义模板的应用程序。

GridView模板是实现ITemplate接口的类。该类定义了将在GridView列中显示的控件,以及数据如何绑定这些控件,同时还能够通过一些特定代码来处理页眉和页脚。就本例而言,将从零开始讲解一个简化的GridView示例,它使用模板格式化GridView的内容。虽然这个示例非常简单,但很多复杂的情况都可以通过扩展该示例实现。下面开始介绍自定义模板类的实现。

1.创建自定义模板类

自定义模板类(名称为CustomGridViewTemplate)包括的代码放置在GridView控件中,这些代码内的控件完成实际工作格式化控件,绑定数据的工作。由于CustomGridViewTemplate类实现ITemplate接口,所以该类提供了InstantiateIn()方法的实现。在该方法中定义了生成包括子控件的GridView控件的行为。示例一列举了该类的实现代码。

示例一:使用自定义模板格式化GridView


Code
 1 public class CustomGridViewTemplate : ITemplate
 2 {
 3     private DataControlRowType _templateType;
 4     private string _columnName;
 5     private string _dataType;
 6     public CustomGridViewTemplate(DataControlRowType templateType,
 7   string columnName, string dataType)
 8     {
 9         _templateType = templateType;
10         _columnName = columnName;
11         _dataType = dataType;
12     }
13     /// <summary>
14     /// 此方法为 GridView执行DataBind方法后触发执行 
15     /// 按行顺序向下执行(行->行中各列)
16     /// </summary>
17     /// <param name="container"></param>
18     public void InstantiateIn(System.Web.UI.Control container)
19     {
20         switch (_templateType)
21         {
22             case DataControlRowType.Header:
23                 //创建当前列的标题
24                 Literal literal = new Literal();
25                 literal.Text = "<b><i><u>" + _columnName + "</u></i></b>";
26                 container.Controls.Add(literal);
27                 break;
28             case DataControlRowType.DataRow:
29                 //创建当前列的一行
30                 Label label = new Label();
31                 switch (_dataType)
32                 {
33                     case "DateTime":
34                         label.ForeColor = System.Drawing.Color.Blue;
35                         break;
36                     case "Double":
37                         label.ForeColor = System.Drawing.Color.Violet;
38                         break;
39                     case "Int32":
40                         label.ForeColor = System.Drawing.Color.Green; ;
41                         break;
42                     case "String":
43                         label.ForeColor = System.Drawing.Color.Brown;
44                         break;
45                     default:
46                         label.ForeColor = System.Drawing.Color.Green;
47                         break;
48                 }
49                 // 注册用于数据绑定的事件处理程序
50                 label.DataBinding += new EventHandler(this.label_DataBinding);
51                 container.Controls.Add(label);
52                 break;
53             default:
54                 break;
55         }
56     }
57 
58     /// <summary>
59     /// 当InstantiateIn执行完一行后,统一触发该绑定事件处理方法
60     /// </summary>
61     /// <param name="sender"></param>
62     /// <param name="e"></param>
63     private void label_DataBinding(Object sender, EventArgs e)
64     {
65         // 获取触发时间的控件
66         Label label = (Label)sender;
67         // 获取容器行
68         GridViewRow row = (GridViewRow)label.NamingContainer;
69         // 获取行数据值,并将其格式化
70         string rawValue = DataBinder.Eval(row.DataItem, _columnName).ToString();
71         switch (_dataType)
72         {
73             case "DateTime":
74                 label.Text = String.Format("{0:d}", DateTime.Parse(rawValue));
75                 break;
76             case "Double":
77                 label.Text = String.Format("{0:###,###,##0.00}",
78                 Double.Parse(rawValue));
79                 break;
80             default:
81                 label.Text = rawValue;
82                 break;
83         }
84     }
85

 


本例仅使用了文本标签来显示数据,但是并不限于单个控件。该方法还通过注册事件处理程序来设置数据绑定:

// 为执行数据绑定注册事件处理程序
label.DataBinding += new EventHandler(this.label_DataBinding);

正如所期待的那样,当数据绑定到GridView时会调用数据绑定事件处理程序。在数据绑定事件处理程序中,获取了指向控件容器的引用,同时还格式化了数据。

2.使用模板

如果将CustomGridViewTemplate类存储到App_Code文件夹中,那么对于Web站点的所有ASP.NET页面而言,都可以使用该类。示例二列举了如何通过GridView控件使用CustomGridViewTemplate。

.CS文件

Code
using System;
using System.Data;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using System.Collections;
using System.Data.SqlClient;
using System.Web.Configuration;

public partial class _Default : System.Web.UI.Page

{

    protected void Page_Load(object sender, EventArgs e)

    {

        if (!IsPostBack)

        {

            string connectionString = WebConfigurationManager.ConnectionStrings["strDBConn"].ConnectionString;

            DataTable deptTable = new DataTable();

            using (SqlConnection connection = new SqlConnection(connectionString))

            {

                string sql = "select * from province";

                SqlCommand command = new SqlCommand(sql);

                command.CommandType = CommandType.Text;

                command.Connection = connection;

                SqlDataAdapter adapter = new SqlDataAdapter();

                adapter.SelectCommand = command;

                adapter.Fill(deptTable);

            }

            // 清除当前存在的列

            //deptView.Columns.Clear();

            // 递归DataTable,将列添加到GridView中
            for (int i = 0; i < deptTable.Columns.Count; i++)

            {

                TemplateField templateField = new TemplateField();

                // 创建数据行
                templateField.ItemTemplate = new CustomGridViewTemplate

                (DataControlRowType.DataRow,

                deptTable.Columns[i].ColumnName,

                deptTable.Columns[i].DataType.Name);

                //创建标题
                templateField.HeaderTemplate = new CustomGridViewTemplate

                (DataControlRowType.Header, deptTable.Columns[i].ColumnName,

                deptTable.Columns[i].DataType.Name);

                // 将其添加到GridView
                deptView.Columns.Add(templateField);

            }

            //绑定并显示数据
            deptView.DataSource = deptTable;

            deptView.DataBind();

            ViewState["DbPrivance"] = deptTable;

        }


    }


    protected void BtnDel_Click(object sender, EventArgs e)

    {

        DataTable deptTable = ViewState["DbPrivance"] as DataTable;

        for (int i = deptView.Rows.Count-1; i >= 0; i--)

        {

            string strID = "";

            CheckBox cbox = deptView.Rows[i].FindControl("CBoxSelected") as CheckBox;

            if (cbox != null)

            {

                bool isChecked = cbox.Checked;

                //调用删除操作方法
            }

        }

        for (int i = 0; i < deptTable.Columns.Count; i++)

        {

            TemplateField templateField = new TemplateField();

            // 创建数据行
            templateField.ItemTemplate = new CustomGridViewTemplate

            (DataControlRowType.DataRow,

            deptTable.Columns[i].ColumnName,

            deptTable.Columns[i].DataType.Name);

            //创建标题
            templateField.HeaderTemplate = new CustomGridViewTemplate

            (DataControlRowType.Header, deptTable.Columns[i].ColumnName,

            deptTable.Columns[i].DataType.Name);

            // 将其添加到GridView
            deptView.Columns.Add(templateField);

        }

        this.deptView.DataSource = deptTable;

        this.deptView.DataBind();

    }

}
public class CustomGridViewTemplate : ITemplate

{

    private DataControlRowType _templateType;

    private string _columnName;

    private string _dataType;

    public CustomGridViewTemplate(DataControlRowType templateType,

  string columnName, string dataType)

    {

        _templateType = templateType;

        _columnName = columnName;

        _dataType = dataType;

    }

    /// <summary>

    /// 此方法为 GridView执行DataBind方法后触发执行 

    /// 按行顺序向下执行(行->行中各列)

    /// </summary>

    /// <param name="container"></param>
    public void InstantiateIn(System.Web.UI.Control container)

    {

        switch (_templateType)

        {

            case DataControlRowType.Header:

                //创建当前列的标题
                Literal literal = new Literal();

                literal.Text = "<b><i><u>" + _columnName + "</u></i></b>";

                container.Controls.Add(literal);

                break;

            case DataControlRowType.DataRow:

                //创建当前列的一行
                Label label = new Label();

                switch (_dataType)

                {

                    case "DateTime":

                        label.ForeColor = System.Drawing.Color.Blue;

                        break;

                    case "Double":

                        label.ForeColor = System.Drawing.Color.Violet;

                        break;

                    case "Int32":

                        label.ForeColor = System.Drawing.Color.Green; ;

                        break;

                    case "String":

                        label.ForeColor = System.Drawing.Color.Brown;

                        break;

                    default:

                        label.ForeColor = System.Drawing.Color.Green;

                        break;

                }

                // 注册用于数据绑定的事件处理程序
                label.DataBinding += new EventHandler(this.label_DataBinding);

                container.Controls.Add(label);

                break;

            default:

                break;

        }

    }


    /// <summary>

    /// 当InstantiateIn执行完一行后,统一触发该绑定事件处理方法

    /// </summary>

    /// <param name="sender"></param>

    /// <param name="e"></param>
    private void label_DataBinding(Object sender, EventArgs e)

    {

        // 获取触发时间的控件
        Label label = (Label)sender;

        // 获取容器行
        GridViewRow row = (GridViewRow)label.NamingContainer;

        // 获取行数据值,并将其格式化
        string rawValue = DataBinder.Eval(row.DataItem, _columnName).ToString();

        switch (_dataType)

        {

            case "DateTime":

                label.Text = String.Format("{0:d}", DateTime.Parse(rawValue));

                break;

            case "Double":

                label.Text = String.Format("{0:###,###,##0.00}",

                Double.Parse(rawValue));

                break;

            default:

                label.Text = rawValue;

                break;

        }

    }

}


 .ASPX文件


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

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">

    <title>Untitled Page</title>
</head>
<body>

    <form id="form1" runat="server">

    <div> 

      <asp:GridView ID="deptView" runat="server" AutoGenerateColumns="False">

          <Columns>

              <asp:TemplateField>

                  <ItemTemplate>

                      <asp:CheckBox ID="CBoxSelected" runat="server" />

                  </ItemTemplate>

              </asp:TemplateField>

          </Columns>

  </asp:GridView> 

        <br />

        <asp:Button ID="BtnDel" runat="server" Text="删除" OnClick="BtnDel_Click" />

        <asp:Button ID="BtnModify" runat="server" Text="修改" /><br />

         </div>

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

 

示例中唯一的技巧是将模板类关联到GridView。这是通过创建新的TemplateField对象,接着为ItemTemplate和HeaderTemplate将TemplateField与CustomGridViewTemplate关联起来实现的。注意,可以使用相同的方法来设置其他模板,例如AlternatingItemTemplate和FooterTemplate。