zoukankan      html  css  js  c++  java
  • 神奇的 DataGrid··········

    作者 Dino Esposito

     

    即使你可能是新接触到ASP.NET编程和数据绑定,但你是完全有可能以数字图表的形式作出有价值的强大的DataGrid控件。简单说,它是把数据格式化为列表式、柱式的控件,它有着极端通用性和很高的可配置性。它自身就有强大的可编程的特征,虽然我已经有一年的使用经验,但我还没发现有不能放在DataGrid Web控件表上的元素。我想和大家一起分享这些小技巧;其中一些甚至可称为“卑鄙的用法”。这些技巧涉及到对DataGrid控件的外表、感觉和它是怎么把信息呈现给用户。

     

    在深入之前,让我阐明可能会引起混淆的关键一点。.NET构架定义了两种风格迥异的DataGrid控件。它们有着相同的名字但属于不同的命名空间。更重要的是,它们除了名字相同之外没就有任何相同之处了。我在本文所讲的DataGrid控件是DataGrid Web控件,它是在System.Web.UI.WebControl 命名空间中被定义的。另外一个DataGrid控件是在Windonws窗体中的DataGrid控件,它是在System.Windows.Forms命名空间中被定义的。它们在相当独立的两个方向发展,即使两者都试图提供一套共同的兼容能力和遵循相似编程模型。Windows窗体的DataGrid控件显示出许多Web DataGrid所不具有特性。同样的,你可以使用Web窗体的DataGrid控件做Windows窗体的DataGrid控件所不能的事。所以在阅读MSDN文档时,小心的查看你所阅读的是哪个控件。

     

    在这篇文章中,我将会讨论并实现下列常遇到的情形的解决方案:

     

    l          如何在最高一行上方建立两行标题,其中一行把相关的内容合在一起,使DataGrid成为更具描述性和信息性的表格。

     

    对我们所要接触的DataGrid控件编程基础有ItemCreated BoundColumnDataFormatString属性和分页栏。

     

    一个两行的标题

    DataGrid控件允许你给绑定到控件上的每一列分配一个标题。标题的文字是使用column类的HeaderText属性。所有的column类,从BoundColumn TemplateColumn、从HyperLinkColumn ButtonColumn都有一个HeaderText的属性。有这样一种情形,然而其中具有大量复杂的数据所以你需要用一个二级的标题显示。这个二级标题在列标题的上方。每一格把二个或更多的下面的列组合在一起。下面的HTML代码(图一)显示我的意思:

     

    <table>

    <tr>

      <td colspan=2>Group 1</td> <td colspan=2>Group 2</td>

    </tr>

    <tr>

      <td>Col #1</td> <td>Col #2</td>

      <td>Col #3</td> <td>Col #4</td>

    </tr>

    <tr>

    <td><i>Contents of the table</i></td>

    </tr>

    </table>

     

    图一:一个简单的两行标题的HTML表格。

     

    在你有复杂的表格要显示时这个特性是相当重要的的,如:发票单,销售报告或统计单。如果你计划使用HTMLASP来完成一个两行的标题是没有问题的。荒谬的是,当你是用ASP.NET来实现它时它变成了技巧了。为了能实现专业的报告,最和情理的方法是使用DataGrid控件。不幸的是,DataGrid控件通过预定义的属性和委派,没有包含双标题的特性。在另一方面,使用DataGrid控件几乎是强制的,因为其它控件如:DataListRepeater没有提供分页和排序功能,但这两个功能对于Web报告来说是很重要的。然而,如果分页和排序对你来说并不是重要的特征的话,DataList控件是你用来建立复杂标题的更简单的工具。

     

    现在你将会看到如何使用SQL Server2000Northwind库中的employee表来建立一个报告,并且它是个人信息和工作相关信息清楚分开的报告。图二显示示例中的DataGrid控件怎样申明列的。

     

    <Columns>

       <asp:TemplateColumn HeaderText="Name">

          <itemtemplate>

              <%# "<b>" + ((DataRowView)Container.DataItem)

                ["lastname"] + "</b>, " +

              ((DataRowView)Container.DataItem)["firstname"]   %>

          </itemtemplate>

       </asp:TemplateColumn>

       <asp:BoundColumn DataField="birthdate" HeaderText="Born"

        DataFormatString="{0:d}" />

       <asp:BoundColumn DataField="country"

        HeaderText="Country" />

       <asp:BoundColumn DataField="title" HeaderText="Title" />

       <asp:BoundColumn DataField="hiredate" HeaderText="Hired"

        DataFormatString="{0:d}" />

    </Columns>

    图二: 示例中DataGrid的列

     

    开始的三列——姓名,生日和籍贯——将会被组织在Personal超级标题下。剩下两个,名称和雇佣时间,被放到Job超级标题下。

     

    DataGrid控件自动提供一行标题的表格。标题也可以使用绘制样式定义的HeaderStyle属性。困难就是DataGrid控件不让你创建标题行。虽然你能定义一个ItemCreated事件的事件处理器,但它只能在标题行的HTML代码已经产生之后才让你有机会去操作它。作为选择,空件的编程界面允许你得到代表标题行的TableRow对象,不过你不能从它得到可靠的父控件:

     

    TableRow rowHeader = (TableRow) e.Item;

     

    你需要一个Table对象——它是ASP.NET控件用于生成表的一个活实例——来添加一个新行。我试了TableRowParent属性,但它总是返回了null.

     

    我尝试的另一种失败的方法是把DataGrid控件封装在一个asp:table控件中。在这个方法中,结果是两个完全分离的表。它更不可能把表的最上行分为包含两个或更多列的行。

     

    神秘的事物就想它看起来那样神秘,解决这个问题的关键竟是分页栏。如果你DataGrid文档小心的检查分页栏的话,你不会在三个不同位置中把分页栏放错。控件默认把它放在栅格栏下。然而,他还可以放在栅格栏之下,当然也可以上下都有。在我追踪ItemCreated 事件处理器,我找出这个仅仅是靠着运气。你可以通过Position属性来控制分页的位置。

     

    grid.PagerStyle.Position = PagerPosition.TopAndBottom;

     

    就像其它ASP.NET控件所做的那样,DataGrid首先准备输出为一串,接着触发PreRender事件,最后生成HTML代码。HTML代码是依照控件属性和在ItemGreated中建立的。我注意到ItemCreated为分页栏调用了两次,最后栅格定义了分页栏作为生成表格第一行和最后一行。当它开始实际地生成时,这些行中的一行或两行将依照分页栏位置和可见性的设置被删除掉。从这里学到了什么呢?如果你设置分页的位置为TopAndBottom,控件将会显示两个同一的更能相似的分页栏:一个在栅格的上方,一个在它的下方(图三)。

     

    图三:两个分页栏的DataGrid控件.

     

    两个分页栏都是栅格表的重要部分,并且都能在ItermCteated事件中被挂起。唯一需要告诫的是你应该分清哪个是第一哪个是第二。如果你的代码挂起了第一个分页栏,你可能想要清除所有的子控件,并且再增加适合的单元格来放置超级标题。如果分页栏截取的是第二个,所有你必须做的就是应用任何你需要的自定义连接。

     

    你怎样指导哪一个分页栏是ItemCreated处理的?你还记得老式的有效的编程工具——全局变量吗?一个老的全局布尔变量的方法如:m_bFirstTime很容易得可以追踪到分页栏是否是第一次被创建。在图四的示例中,ItemCreated判断分页栏再次对话中是否是第一次被创建,如果是,在第一个(且是唯一一个)行的单元格中移除所有的控件。注意ItemCreated总是调用两次分页栏,并不考虑分配给Position的值。这个组合分页格(现在是第一个超级标题格)能从Header中继承某些样式(如:颜色、字体和边框等)并且重写某些部分。MergeStyle提供了这个方法。

     

    private bool m_bFirstTime = true;

    public void ItemCreated(Object sender,

     DataGridItemEventArgs e)

    {

      ListItemType elemType = e.Item.ItemType;

      if (elemType == ListItemType.Pager)

      {

        if (m_bFirstTime)

        {

          // Personal header

          TableCell cell0 = (TableCell) e.Item.Controls[0];

          cell0.Controls.Clear();

          cell0.MergeStyle(grid.HeaderStyle);

          cell0.BackColor = Color.Navy;

          cell0.ForeColor = Color.Yellow;

          cell0.ColumnSpan = 3;

          cell0.HorizontalAlign = HorizontalAlign.Center;

          cell0.Controls.Add(new LiteralControl("Personal"));

     

          // Job header

          TableCell cell1 = new TableCell();

          cell1.MergeStyle(grid.HeaderStyle);

          cell1.BackColor = Color.Navy;

          cell1.ForeColor = Color.Yellow;

          cell1.ColumnSpan = 2;

          cell1.HorizontalAlign = HorizontalAlign.Center;

          cell1.Controls.Add(new LiteralControl("Job"));

          e.Item.Controls.Add(cell1);

          m_bFirstTime = false;

        }

        else

        {  TableCell pager = (TableCell) e.Item.Controls[0];

     

          // Loop through the pager buttons skipping

          // over blanks

          // (Blanks are treated as LiteralControl(s)

          for (int i=0; i<pager.Controls.Count; i+=2)

          {

            Object o = pager.Controls[i];

            if (o is LinkButton)

             {

              LinkButton h = (LinkButton) o;

              h.Text = "[ " + h.Text + " ]";

            }

          else

            {

              Label l = (Label) o;

              l.Text = "Page " + l.Text;

            }

          }

          m_bFirstTime = true;

        }

      }

    图四:ItemCreated事件处理使分页栏加到了标题行里。

     

    超级标题格的ColumSpan属性必须被设置为期望组合在一起的列的数目,最终,单元格通过文字控件被附上文字。当你截取分页栏时,它只包含一格。因此,如果你需要更多的第一级标题的话,新格必须被创建。这些值的总数被分配给ColumnSpan属性,所有单元格必须和栅格中的列匹配。当你这样做时,不要忘记设置m_bFirstTime变量为False。同样的,不要忘记当你重新建立第二个分页时把这个全局变量重置为True。如果你忽略了这一步,你将会在页间移动时遇到标题的问题。图五显示了有两个标题栏的DataGrid控件。

     

    图五:使用重写最上的分页栏产生的标题栏。

     

    结论

    DataGrid控件是一个非常复杂的控件。它是一个有着丰富特征和可能性的一个宝库,包括已列为文档的和没有列为文档的,被发现的和没有被发现的。为了寻找一些实用的代码技巧,我希望我已经在控件内在使用上给出了一些提示。

  • 相关阅读:
    SSL JudgeOnline 1194——最佳乘车
    SSL JudgeOnline 1457——翻币问题
    SSL JudgeOnlie 2324——细胞问题
    SSL JudgeOnline 1456——骑士旅行
    SSL JudgeOnline 1455——电子老鼠闯迷宫
    SSL JudgeOnline 2253——新型计算器
    SSL JudgeOnline 1198——求逆序对数
    SSL JudgeOnline 1099——USACO 1.4 母亲的牛奶
    SSL JudgeOnline 1668——小车载人问题
    SSL JudgeOnline 1089——USACO 1.2 方块转换
  • 原文地址:https://www.cnblogs.com/Fooo/p/534256.html
Copyright © 2011-2022 走看看