在Asp.Net Gridview中分组数据 - c#

我有两个存储过程,它们将返回两组相关数据。数据就是这样。
First Procedure这样返回数据

ISSUE_ID          ISSUETYPE          
-------------------------------------
1            ISSUE 1 TYPE
2            ISSUE 2 TYPE
3            ISSUE 3 TYPE
4            ISSUE 4 TYPE

第二个过程基于ISSUE_ID返回类似的数据

HEADER ID          HEADER NAME            ISSUE_ID       
-----------------------------------------------------
 1                 HEADER 1 NAME               1   
 2                 HEADER 2 NAME               1
 3                 HEADER 3 NAME               2   
 4                 HEADER 4 NAME               2   
 5                 HEADER 5 NAME               3

问题是如何基于ISSUE_ID对其进行分组,并使用两个存储过程将其按组显示在gridview中。我在很多论坛上都用谷歌搜索,我发现选项是嵌套的gridview。我可以不使用此嵌套的gridview来实现吗?

最后,我想像这样在gridview中显示。

ISSUE 1 TYPE
-----------------------------
            HEADER 1 NAME                 
            HEADER 2 NAME 
ISSUE 2 TYPE
-----------------------------
            HEADER 3 NAME                 
            HEADER 4 NAME                  
ISSUE 3 TYPE
-----------------------------
            HEADER 5 NAME                 

在此先感谢百万。.需要一些建议才能实现这一目标。

参考方案

ASP.Net GridView中的分组示例

<asp:GridView ID="grdViewOrders" CssClass="serh-grid" runat="server" AutoGenerateColumns="False" 
              TabIndex="1" Width="100%" CellPadding="4" ForeColor="Black" GridLines="Vertical" 
              BackColor="White" BorderColor="#DEDFDE" BorderStyle="None" BorderWidth="1px"
              OnRowDataBound="grdViewOrders_RowDataBound" OnRowCommand="grdViewOrders_RowCommand" 
              OnRowCreated="grdViewOrders_RowCreated">
    <Columns>       
        <asp:BoundField DataField="OrderID" HeaderText="OrderID" SortExpression="OrderID" />            
        <asp:BoundField DataField="ProductName" HeaderText="ProductName" SortExpression="ProductName" />            
        <asp:BoundField DataField="UnitPrice" HeaderText="UnitPrice" SortExpression="UnitPrice" />          
        <asp:BoundField DataField="Quantity" HeaderText="Quantity" SortExpression="Quantity" />         
        <asp:BoundField DataField="Discount" HeaderText="Discount" SortExpression="Discount" />         
        <asp:BoundField DataField="Amount" HeaderText="Amount" SortExpression="Amount" />                       
    </Columns>      
    <FooterStyle BackColor="#CCCC99" />     
    <SelectedRowStyle CssClass="grid-sltrow" />     
    <HeaderStyle BackColor="#6B696B" Font-Bold="True" ForeColor="White" BorderStyle="Solid" BorderWidth="1px" BorderColor="Black" />        
</asp:GridView>

在Asp.Net Gridview中分组数据 - c#

笔记:

主要逻辑在GridView的RowCreated和RowDataBound事件中。
在遍历所有行的同时

偷看CustomerId(主索引)并检查其他行。
跟踪正在运行的GrandTotal
跟踪正在运行的小计

在遍历结果集的每个点,主索引都会更改:

添加小计行
重置小计准备下一组

标题在GridView中显示为新行。

GridView助手

使用GridViewHelper

在下面,我们将看到一些GridViewHelper示例。首先,我们显示将在其中创建组和摘要的网格。示例数据来自Northwind数据库,进行了一些修改:

在Asp.Net Gridview中分组数据 - c#

要为ItemTotal列创建摘要,我们只需要承诺的2行代码:

protected void Page_Load(object sender, EventArgs e)
{
    GridViewHelper helper = new GridViewHelper(this.GridView1);
    helper.RegisterSummary("ItemTotal", SummaryOperation.Sum);
}

首先,我们创建GridViewHelper来设置将在构造函数中起作用的网格。然后,我们注册指定列名称的摘要以及要执行的摘要操作。结果如下:

在Asp.Net Gridview中分组数据 - c#

在此示例中,添加了新行以显示摘要。另一种选择是使用页脚行显示摘要,而不是创建新的摘要。将新行添加到网格时,仅创建显示汇总列所需的单元格。使用页脚创建所有单元。对于组摘要,所有单元格或仅所需单元格的生成是组属性。

现在我们将创建一个组。代码如下所示:

protected void Page_Load(object sender, EventArgs e)
{
    GridViewHelper helper = new GridViewHelper(this.GridView1);
    helper.RegisterGroup("ShipRegion", true, true);
    helper.ApplyGroupSort();
}

RegisterGroup方法的第一个参数定义必须向其创建组的列。也可以创建一个由一组列组成的复合组。第二个参数指定组是否为自动。在这种情况下,将自动为组标题创建一个新行。第三个参数指定是否必须隐藏组列。 ApplyGroupSort方法将网格的排序表达式设置为组列,在本例中为ShipRegion。这是分组正常工作所必需的,除非数据是从数据库中订购的。

在上面的示例中,ShipRegion列已被隐藏:

在Asp.Net Gridview中分组数据 - c#

让我们做点更有趣的事情,向创建的组添加一个摘要。我们只需要多一行就可以将摘要注册到该组:

protected void Page_Load(object sender, EventArgs e)
{
    GridViewHelper helper = new GridViewHelper(this.GridView1);
    helper.RegisterGroup("ShipRegion", true, true);
    helper.RegisterSummary("ItemTotal", SummaryOperation.Sum, "ShipRegion");
    helper.ApplyGroupSort();
}

这次,RegisterSummary方法采用了另一个参数。该参数指定摘要必须创建到的组的名称。组名是根据组列名自动生成的。如果组只有一列,则组名将是该列的名称。如果该组具有多个列,则组名将是组成该组的列的有序串联,并以加号(“ +”):“ ShipRegion + ShipName”联接。

我们可以在网格下方看到带有分组和分组摘要的网格:

在Asp.Net Gridview中分组数据 - c#

可以在网格中创建多个组,以模拟分层分组,如下所示:

protected void Page_Load(object sender, EventArgs e)
{
    GridViewHelper helper = new GridViewHelper(this.GridView1);
    helper.RegisterGroup("ShipRegion", true, true);
    helper.RegisterGroup("ShipName", true, true);
    helper.ApplyGroupSort();
}

结果:

在Asp.Net Gridview中分组数据 - c#

当存在多个组时,可视化会受到影响。 GridViewHelper具有事件,可轻松实现视觉或功能调整。事件列表如下:

GroupStart:在新的组开始时发生,表示在组列中找到新值时。
GroupEnd:发生在组的最后一行
GroupHeader:在为组添加自动标题行时发生。如果组不是自动的,则不会触发该事件。
GroupSummary:在为组生成摘要行时发生。如果该组不是自动组,则不会触发该事件,但如果该组是抑制组,则将触发该事件(稍后会看到)。
GeneralSummary:在计算一般摘要之后发生。如果摘要是自动的,则事件在添加摘要行之后以及将摘要值放入该行之后发生。
FooterDataBound:在页脚数据绑定中发生。

再增加几行代码,我们可以改善网格的外观:

protected void Page_Load(object sender, EventArgs e)
{
    GridViewHelper helper = new GridViewHelper(this.GridView1);
    helper.RegisterGroup("ShipRegion", true, true);
    helper.RegisterGroup("ShipName", true, true);
    helper.GroupHeader += new GroupEvent(helper_GroupHeader);
    helper.ApplyGroupSort();
}

private void helper_GroupHeader(string groupName, object[] values, GridViewRow row)
{
    if ( groupName == "ShipRegion" )
    {
        row.BackColor = Color.LightGray;
        row.Cells[0].Text = "&nbsp;&nbsp;" + row.Cells[0].Text;
    }
    else if (groupName == "ShipName")
    {
        row.BackColor = Color.FromArgb(236, 236, 236);
        row.Cells[0].Text = "&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;" + row.Cells[0].Text;
    }
}

化妆品后的格:

在Asp.Net Gridview中分组数据 - c#

更多分组选项

还有两个有趣的示例。第一个提出了一个复合小组。第二个定义了一个抑制组,其行为与sql GROUP BY子句相同。重复值被抑制,并且对其他列执行汇总操作。

下面我们可以看到复合组的代码和网格外观:

protected void Page_Load(object sender, EventArgs e)
{
    GridViewHelper helper = new GridViewHelper(this.GridView1);
    string[] cols = new string[2];
    cols[0] = "ShipRegion";
    cols[1] = "ShipName";
    helper.RegisterGroup(cols, true, true);
    helper.ApplyGroupSort();
}

在Asp.Net Gridview中分组数据 - c#

我们可以向该组添加摘要。这次,我们将定义一个平均操作并添加标签以指示该操作:

protected void Page_Load(object sender, EventArgs e)
{
    GridViewHelper helper = new GridViewHelper(this.GridView1);
    string[] cols = new string[2];
    cols[0] = "ShipRegion";
    cols[1] = "ShipName";
    helper.RegisterGroup(cols, true, true);
    helper.RegisterSummary("ItemTotal", SummaryOperation.Avg, "ShipRegion+ShipName");
    helper.GroupSummary += new GroupEvent(helper_GroupSummary);
    helper.ApplyGroupSort();
}

private void helper_GroupSummary(string groupName, object[] values, GridViewRow row)
{
    row.Cells[0].HorizontalAlign = HorizontalAlign.Right;
    row.Cells[0].Text = "Average";
}

在Asp.Net Gridview中分组数据 - c#

最后一个样本将创建一个抑制组。值得一提的是,如果定义了抑制组,则不能创建其他组。同样,如果已经定义了一个组,则无法创建抑制组,如果尝试,则将引发异常。

下面我们可以看到抑制组的代码和网格外观:

protected void Page_Load(object sender, EventArgs e)
{
    GridViewHelper helper = new GridViewHelper(this.GridView1);
    helper.SetSuppressGroup("ShipName");
    helper.RegisterSummary("Quantity", SummaryOperation.Sum, "ShipName");
    helper.RegisterSummary("ItemTotal", SummaryOperation.Sum, "ShipName");
    helper.ApplyGroupSort();
}

在Asp.Net Gridview中分组数据 - c#

没有定义汇总操作的列将不显示任何值。这是有道理的,因为GridViewHelper不知道如何继续将在组行中找到的值汇总为唯一值。这提醒了某些已知消息:

“列'column_name'在选择列表中无效,因为它既不包含在聚合函数中也不在GROUP BY子句中。”

显示没有汇总操作的列是没有意义的,要隐藏它们,我们需要调用一个方法:

protected void Page_Load(object sender, EventArgs e)
{
    GridViewHelper helper = new GridViewHelper(this.GridView1);
    helper.SetSuppressGroup(rdBtnLstGroup.SelectedValue);
    helper.RegisterSummary("Quantity", SummaryOperation.Sum, "ShipName");
    helper.RegisterSummary("ItemTotal", SummaryOperation.Sum, "ShipName");
    helper.SetInvisibleColumnsWithoutGroupSummary();
    helper.ApplyGroupSort();
}

我知道,这是个大牌!生成的网格如下所示:

在Asp.Net Gridview中分组数据 - c#

摘要操作

GridViewHelper具有三个内置的摘要操作:求和,平均值和行数。一个非常有用的功能是可以定义自定义摘要操作。为此,我们需要为GridViewHelper提供两种方法。对于在网格(或组)中找到的每一行,将调用一个方法,将调用另一种方法以检索汇总操作的结果。下面是自定义汇总操作的示例。半虚拟操作将返回找到的最小值:

private List<int> mQuantities = new List<int>();

protected void Page_Load(object sender, EventArgs e)
{
    GridViewHelper helper = new GridViewHelper(this.GridView1);
    helper.RegisterSummary("Quantity", SaveQuantity, GetMinQuantity);
}

private void SaveQuantity(string column, string group, object value)
{
    mQuantities.Add(Convert.ToInt32(value));
}

private object GetMinQuantity(string column, string group)
{
    int[] qArray = new int[mQuantities.Count];
    mQuantities.CopyTo(qArray);
    Array.Sort(qArray);
    return qArray[0];
}

在上面的代码中,我们可以看到所需的方法签名。两者都接收汇总的组名和列名。如果摘要不是相对于组的,则group参数将为null。为网格中找到的每一行调用的方法还接收当前行中的列的值。

生成的网格如下所示:

在Asp.Net Gridview中分组数据 - c#

局限性

在一个示例中,我们说我们可以模拟分层分组。尽管网格似乎呈现了分层的分组,但是实际的实现不是分层的。没有组或子组。只有顺序注册的组。如果我们需要为内部组创建摘要,这将成为一个问题。下面我们可以看到在这种情况下会发生什么:

protected void Page_Load(object sender, EventArgs e)
{
    GridViewHelper helper = new GridViewHelper(this.GridView1);
    helper.RegisterGroup("ShipRegion", true, true);
    helper.RegisterGroup("ShipName", true, true);
    helper.RegisterSummary("ItemTotal", SummaryOperation.Sum, "ShipName");
    helper.RegisterSummary("ItemTotal", SummaryOperation.Sum);
    helper.GroupSummary += new GroupEvent(helper_Bug);
    helper.ApplyGroupSort();
}

private void helper_Bug(string groupName, object[] values, GridViewRow row)
{
    if (groupName == null) return;

    row.BackColor = Color.Bisque;
    row.Cells[0].HorizontalAlign = HorizontalAlign.Center;
    row.Cells[0].Text = "[ Summary for " + groupName + " " + values[0] + " ]";
}

在Asp.Net Gridview中分组数据 - c#

如我们所见,摘要是在外部组的标题之后创建的。发生这种情况是因为事件顺序是:

Group1_Start
Group1_End
Group2_Start
Group2_End

对于分层分组,事件序列应为:

Group1_Start
Group2_Start
Group2_End
Group1_End

实作

GridViewHelper被实现为独立类,而不是继承的类。这使得可以将GridViewHelper与任何GridView一起使用,并且不会强制开发人员继承特定的GridView,这可能会影响类的设计。解决方案中还有另外四个类:GridViewSummary,GridViewGroup,GridViewSummaryList和GridViewGroupList。创建“列表”类以允许字符串索引器进行访问:helper.GeneralSummaries [“ ItemTotal”]。Value。

创建GridViewHelper时,将保存对目标GridView的引用,并且RowDataBound事件绑定到执行艰苦工作的方法:

public GridViewHelper(GridView grd, bool useFooterForGeneralSummaries, SortDirection groupSortDirection)
{
    this.mGrid = grd;
    this.useFooter = useFooterForGeneralSummaries;
    this.groupSortDir = groupSortDirection;
    this.mGeneralSummaries = new GridViewSummaryList();
    this.mGroups = new GridViewGroupList();
    this.mGrid.RowDataBound += new GridViewRowEventHandler(RowDataBoundHandler);
}

GridViewHelper内部使用的某些方法已公开定义,因为它们提供了一些自定义可能需要的有用功能。示例中未显示其他一些选项,但可以使用Visual Studio intellisense轻松验证。

已知的问题

过多的装箱和拆箱值类型可能会影响性能。为了解决这个问题,我们可以使用泛型实现内置的摘要操作,但这并不像我们想要的那样容易,如使用泛型进行计算所见。另一种可能性:运算符重载泛型。在现实生活中,除非有一百万行或有数千个用户同时对数据进行分组和汇总,否则这不会影响应用程序。

在线示例使GridView EnableViewState保持为false。这是必需的,因为当EnableViewState为true时,如果页面位于PostBack中,则将从ViewState重建GridView,并且不会触发RowDataBound事件。我们可以安全地禁用ASP.Net 2.0中的ViewState,因为ControlState仍将保存。

在Asp.Net MVC Razor中将HTML视图作为电子邮件附件发送 - javascript

我目前在Razor ASP.Net MVC工作。在这里,我有一个HTML view,名为“客户付款”,它是根据某些计算在RAZOR中生成的,并显示在HTML dialog中。我想将此Html View作为电子邮件附件发送。但是在这里,我感到困惑,我不得不将这个HTML View转移到.PDF or .jpg中的某些jQuery中,然后将其发送到Control…

当回复有时是一个对象有时是一个数组时,如何在使用改造时解析JSON回复? - java

我正在使用Retrofit来获取JSON答复。这是我实施的一部分-@GET("/api/report/list") Observable<Bills> listBill(@Query("employee_id") String employeeID); 而条例草案类是-public static class…

在ASP.NET WebForms中在服务器端初始化bootsrap datatimepicker - javascript

我有这个HTML<div class='datepicker input-group date' id='datetimepickerStart'> <input type='text' class="form-control" /> <span c…

如何在ASP.NET Page_Load事件中识别RadButton启动回发的原因? - c#

在我的ASP.NET页的Page_Load中,我试图确定某个按钮是否已单击并尝试回发:if (Page.IsPostBack) { if (Request.Params.Get("__EVENTARGUMENT") == "doStuff") doSomething(); } doStuff是标记内的JavaScrip…

java.net.URI.create异常 - java

java.net.URI.create("http://adserver.adtech.de/adlink|3.0") 抛出java.net.URISyntaxException: Illegal character in path at index 32: http://adserver.adtech.de/adlink|3.0 虽然n…