如何仅在数据不为空时显示 DataGrid 页眉和页脚行 (vb.net)
How to show DataGrid header and footer row only when data is NOT EMPTY (vb.net)
我见过许多关于如何在网格 return 没有数据时显示页眉 and/or 页脚行的 .NET 解决方案。我想做相反的事情,当数据被 returned(通过 sql 存储过程)时,然后在后面的代码中对每一列进行总计,并在页脚行中显示总计,但隐藏页眉和页脚之间的每一行。为什么?因为我还没有弄清楚如何(在 SQL 中)求和,在使用参数时求和,否则我会简单地 return 单行中的最终总和并在网格中显示一行。更好的解决方案可能是重写我的 SQL 查询,但由于我对高级 SQL 的理解有限,我选择 在代码后面(不是 GridView)中对 DataGrid 列求和并显示在页脚中, 同时隐藏除页眉和页脚之外的所有行。
所以我的问题是,是否可以对 DataGrid 列进行总计,在页脚显示总计但隐藏其他数据行?
SQL 存储过程
SELECT [EmpID]
, EmpName
, tblCodes.CodeID
, [Timecode]
, SUM(Hours) AS SumTotal
, SUM(CASE WHEN tblCodes.CodeID IN (4,6,7,8,9,10,11,12,13,14,15,17,20, 21,22,24,25,26) THEN Hours ELSE 0 end) as HOURS
, SUM(CASE WHEN tblCodes.CodeID IN (5,23) THEN Hours ELSE 0 end) As SBY
, SUM(CASE WHEN tblCodes.CodeID IN (1,16)THEN Hours ELSE 0 end) As OT_CT
, SUM(CASE WHEN tblCodes.CodeID IN (3)THEN Hours ELSE 0 end) As OOL
FROM [TLS].[dbo].[vwTimeSummary]
JOIN tblCodes on vwTimeSummary.TimeCode = tblCodes.CodeName
WHERE DayDate BETWEEN @StartDate AND @StopDate
GROUP BY
ID,Emp, tblCodes.idsCodeID, Timecode
HAVING
EmpName = @EmpName
.ASPX 数据网格
<asp:datagrid id="dgdSumHours" runat="server"
Width="250px"
Height="91px"
Font-Names="Tahoma, Arial"
Font-Size="Small"
AutoGenerateColumns="False" Caption="Summary of Hours" ShowFooter="True">
<AlternatingItemStyle BackColor="#EBF5FF"></AlternatingItemStyle>
<headerStyle Font-Bold="True" HorizontalAlign="Center" BackColor="#333333"
ForeColor="White"></headerStyle>
<Columns>
<asp:BoundColumn DataField="HOURS" HeaderText="Hours" DataFormatString="{0:#.00}"></asp:BoundColumn>
<asp:BoundColumn DataField="SBY" HeaderText="Standby" DataFormatString="{0:#.00}"></asp:BoundColumn>
<asp:BoundColumn DataField="OT_CT" HeaderText="Over & Comp time" DataFormatString="{0:#.00}"></asp:BoundColumn>
<asp:BoundColumn DataField="OOL" HeaderText="Out of Level" DataFormatString="{0:#.00}"></asp:BoundColumn>
</Columns>
</asp:datagrid>
.ASPX.VB
Protected Sub dgdSumHours_ItemDataBound(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.DataGridItemEventArgs) Handles dgdSumHours.ItemDataBound
'public variables declared at top of class
'dSumHours
'dStandbyHrs
'dOOLHrs
'dOT_CTEHrs
If e.Item.ItemType = ListItemType.Item Or _
e.Item.ItemType = ListItemType.AlternatingItem Then
'sum all columns
dSumHrs += Convert.ToDecimal(DataBinder.Eval(e.Item.DataItem, "HOURS"))
dStandbyHrs += Convert.ToDecimal(DataBinder.Eval(e.Item.DataItem, "SBY"))
dOOLHrs += Convert.ToDecimal(DataBinder.Eval(e.Item.DataItem, "OOL"))
dOT_CTEHrs += Convert.ToDecimal(DataBinder.Eval(e.Item.DataItem, "OT_CT"))
ElseIf e.Item.ItemType = ListItemType.Footer Then
e.Item.Cells(0).Text = String.Format("{0:#,##0.00}", dSumHrs)
e.Item.Cells(1).Text = String.Format("{0:#,##0.00}", dStandbyHrs)
e.Item.Cells(2).Text = String.Format("{0:#,##0.00}", dOT_CTEHrs)
e.Item.Cells(3).Text = String.Format("{0:#,##0.00}", dOOLHrs)
dSumHrs = 0
dStandbyHrs = 0
dOOLHrs = 0
dOT_CTEHrs = 0
End If
End Sub
更新:使用 CSS 样式有一种方法可以隐藏行并且仍然能够从后面的代码访问行中的数据,但是它会在隐藏的页眉和页脚行之间留下间隙行谎言。如果数据 return 有很多行,这是有问题的。
应用此 CSS 样式:
.boundfield-hidden {
display: none;}
到每个绑定列' ItemStyle-CssClassproperty=boundfield-hidden
我还是想知道有没有人有更好的解决方案?
我能够使用 Do while 循环读取 DataGrid 的自定义 DataBinding 事件*中的 SqlDataReader 并将这些值传递给全局变量,从而达到预期的效果。然后在 DataGrid 的 _ItemDataBound
事件中,如果行是 .Item
或 .AlternatingItem
,则跳过获取总计的例程,并直接转到 .Footer
行以填充该行中的单元格来自全局变量。
修改了 _ItemDataBound 代码:
Protected Sub dgdSumHours_ItemDataBound(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.DataGridItemEventArgs) Handles dgdSumHours.ItemDataBound
'public variables declared at top of class
'dSumHrs
'dStandbyHrs
'dOOLHrs
'dOT_CTEHrs
If e.Item.ItemType = ListItemType.Item Or _
e.Item.ItemType = ListItemType.AlternatingItem Then
'** comment out this bit of code: *** sum all columns
'dSumHrs += Convert.ToDecimal(DataBinder.Eval(e.Item.DataItem, "HOURS"))
'dStandbyHrs += Convert.ToDecimal(DataBinder.Eval(e.Item.DataItem, "SBY"))
'dOOLHrs += Convert.ToDecimal(DataBinder.Eval(e.Item.DataItem, "OOL"))
'dOT_CTEHrs += Convert.ToDecimal(DataBinder.Eval(e.Item.DataItem, "OT_CT"))
ElseIf e.Item.ItemType = ListItemType.Footer Then
e.Item.Cells(0).Text = String.Format("{0:#,##0.00}", dSumHrs)
e.Item.Cells(1).Text = String.Format("{0:#,##0.00}", dStandbyHrs)
e.Item.Cells(2).Text = String.Format("{0:#,##0.00}", dOT_CTEHrs)
e.Item.Cells(3).Text = String.Format("{0:#,##0.00}", dOOLHrs)
dSumHrs = 0
dStandbyHrs = 0
dOOLHrs = 0
dOT_CTEHrs = 0
End If
End Sub
*自定义数据绑定事件:
'Fill DataGrid, dgdEmpSumHours
Sub dgdEmpSumHours_BindData()
Try
'connection
Using cn As SqlConnection = New SqlConnection(cStr)
'open connection
cn.Open()
'command
Dim cmd As SqlClient.SqlCommand = New SqlClient.SqlCommand("storedprocedurename", conn)
cmd.CommandType = CommandType.StoredProcedure
'pass input parameter
cmd.Parameters.Add("@EmpName", SqlDbType.VarChar).Value = ddwnEmpList.SelectedValue
cmd.Parameters.Add("@BStartDate", SqlDbType.VarChar).Value = PayPeriodBegDate()
cmd.Parameters.Add("@StopDate", SqlDbType.VarChar).Value = PayPeriodEndDate()
'execute(Query)
Dim reader As System.Data.SqlClient.SqlDataReader = cmd.ExecuteReader(CommandBehavior.CloseConnection)
dgdEmpSumHours.DataSource = reader
If (reader.HasRows) Then
Do While (reader.Read())
If IsDBNull(reader.Item("HOURS")) Then
dSumHours = 0
Else
dSumHours += reader.Item("HOURS")
End If
'
If IsDBNull(reader.Item("SBY")) Then
dStandbyHrs = 0
Else
dStandbyHrs += reader.Item("SBY")
End If
'
If IsDBNull(reader.Item("OTCT")) Then
dOT_CTEHrs = 0
Else
dOT_CTEHrs += reader.Item("OTCT")
End If
'
If IsDBNull(reader.Item("OOL")) Then
dOOLHrs = 0
Else
dOOLHrs += reader.Item("OOL")
End If
Loop
Else
ScriptManager.RegisterClientScriptBlock(Me, GetType(Page), "showalert", "alert('Oops, there is a problem displaying Summary of Hours table')", True)
End If
dgdEmpSumHours.DataBind()
End Using
Catch ex As System.Data.SqlClient.SqlException
'message about exception here
ScriptManager.RegisterClientScriptBlock(Me, GetType(Page), "script", "alert('A SQL Exception occurred: ' + ex.Message + '.')", True)
End Try
End Sub
免责声明:此版本的代码中可能存在拼写错误,这是我对它进行通用化的努力。它在我的环境中正常工作。
我见过许多关于如何在网格 return 没有数据时显示页眉 and/or 页脚行的 .NET 解决方案。我想做相反的事情,当数据被 returned(通过 sql 存储过程)时,然后在后面的代码中对每一列进行总计,并在页脚行中显示总计,但隐藏页眉和页脚之间的每一行。为什么?因为我还没有弄清楚如何(在 SQL 中)求和,在使用参数时求和,否则我会简单地 return 单行中的最终总和并在网格中显示一行。更好的解决方案可能是重写我的 SQL 查询,但由于我对高级 SQL 的理解有限,我选择 在代码后面(不是 GridView)中对 DataGrid 列求和并显示在页脚中, 同时隐藏除页眉和页脚之外的所有行。
所以我的问题是,是否可以对 DataGrid 列进行总计,在页脚显示总计但隐藏其他数据行?
SQL 存储过程
SELECT [EmpID]
, EmpName
, tblCodes.CodeID
, [Timecode]
, SUM(Hours) AS SumTotal
, SUM(CASE WHEN tblCodes.CodeID IN (4,6,7,8,9,10,11,12,13,14,15,17,20, 21,22,24,25,26) THEN Hours ELSE 0 end) as HOURS
, SUM(CASE WHEN tblCodes.CodeID IN (5,23) THEN Hours ELSE 0 end) As SBY
, SUM(CASE WHEN tblCodes.CodeID IN (1,16)THEN Hours ELSE 0 end) As OT_CT
, SUM(CASE WHEN tblCodes.CodeID IN (3)THEN Hours ELSE 0 end) As OOL
FROM [TLS].[dbo].[vwTimeSummary]
JOIN tblCodes on vwTimeSummary.TimeCode = tblCodes.CodeName
WHERE DayDate BETWEEN @StartDate AND @StopDate
GROUP BY
ID,Emp, tblCodes.idsCodeID, Timecode
HAVING
EmpName = @EmpName
.ASPX 数据网格
<asp:datagrid id="dgdSumHours" runat="server"
Width="250px"
Height="91px"
Font-Names="Tahoma, Arial"
Font-Size="Small"
AutoGenerateColumns="False" Caption="Summary of Hours" ShowFooter="True">
<AlternatingItemStyle BackColor="#EBF5FF"></AlternatingItemStyle>
<headerStyle Font-Bold="True" HorizontalAlign="Center" BackColor="#333333"
ForeColor="White"></headerStyle>
<Columns>
<asp:BoundColumn DataField="HOURS" HeaderText="Hours" DataFormatString="{0:#.00}"></asp:BoundColumn>
<asp:BoundColumn DataField="SBY" HeaderText="Standby" DataFormatString="{0:#.00}"></asp:BoundColumn>
<asp:BoundColumn DataField="OT_CT" HeaderText="Over & Comp time" DataFormatString="{0:#.00}"></asp:BoundColumn>
<asp:BoundColumn DataField="OOL" HeaderText="Out of Level" DataFormatString="{0:#.00}"></asp:BoundColumn>
</Columns>
</asp:datagrid>
.ASPX.VB
Protected Sub dgdSumHours_ItemDataBound(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.DataGridItemEventArgs) Handles dgdSumHours.ItemDataBound
'public variables declared at top of class
'dSumHours
'dStandbyHrs
'dOOLHrs
'dOT_CTEHrs
If e.Item.ItemType = ListItemType.Item Or _
e.Item.ItemType = ListItemType.AlternatingItem Then
'sum all columns
dSumHrs += Convert.ToDecimal(DataBinder.Eval(e.Item.DataItem, "HOURS"))
dStandbyHrs += Convert.ToDecimal(DataBinder.Eval(e.Item.DataItem, "SBY"))
dOOLHrs += Convert.ToDecimal(DataBinder.Eval(e.Item.DataItem, "OOL"))
dOT_CTEHrs += Convert.ToDecimal(DataBinder.Eval(e.Item.DataItem, "OT_CT"))
ElseIf e.Item.ItemType = ListItemType.Footer Then
e.Item.Cells(0).Text = String.Format("{0:#,##0.00}", dSumHrs)
e.Item.Cells(1).Text = String.Format("{0:#,##0.00}", dStandbyHrs)
e.Item.Cells(2).Text = String.Format("{0:#,##0.00}", dOT_CTEHrs)
e.Item.Cells(3).Text = String.Format("{0:#,##0.00}", dOOLHrs)
dSumHrs = 0
dStandbyHrs = 0
dOOLHrs = 0
dOT_CTEHrs = 0
End If
End Sub
更新:使用 CSS 样式有一种方法可以隐藏行并且仍然能够从后面的代码访问行中的数据,但是它会在隐藏的页眉和页脚行之间留下间隙行谎言。如果数据 return 有很多行,这是有问题的。
应用此 CSS 样式:
.boundfield-hidden {
display: none;}
到每个绑定列' ItemStyle-CssClassproperty=boundfield-hidden
我还是想知道有没有人有更好的解决方案?
我能够使用 Do while 循环读取 DataGrid 的自定义 DataBinding 事件*中的 SqlDataReader 并将这些值传递给全局变量,从而达到预期的效果。然后在 DataGrid 的 _ItemDataBound
事件中,如果行是 .Item
或 .AlternatingItem
,则跳过获取总计的例程,并直接转到 .Footer
行以填充该行中的单元格来自全局变量。
修改了 _ItemDataBound 代码:
Protected Sub dgdSumHours_ItemDataBound(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.DataGridItemEventArgs) Handles dgdSumHours.ItemDataBound
'public variables declared at top of class
'dSumHrs
'dStandbyHrs
'dOOLHrs
'dOT_CTEHrs
If e.Item.ItemType = ListItemType.Item Or _
e.Item.ItemType = ListItemType.AlternatingItem Then
'** comment out this bit of code: *** sum all columns
'dSumHrs += Convert.ToDecimal(DataBinder.Eval(e.Item.DataItem, "HOURS"))
'dStandbyHrs += Convert.ToDecimal(DataBinder.Eval(e.Item.DataItem, "SBY"))
'dOOLHrs += Convert.ToDecimal(DataBinder.Eval(e.Item.DataItem, "OOL"))
'dOT_CTEHrs += Convert.ToDecimal(DataBinder.Eval(e.Item.DataItem, "OT_CT"))
ElseIf e.Item.ItemType = ListItemType.Footer Then
e.Item.Cells(0).Text = String.Format("{0:#,##0.00}", dSumHrs)
e.Item.Cells(1).Text = String.Format("{0:#,##0.00}", dStandbyHrs)
e.Item.Cells(2).Text = String.Format("{0:#,##0.00}", dOT_CTEHrs)
e.Item.Cells(3).Text = String.Format("{0:#,##0.00}", dOOLHrs)
dSumHrs = 0
dStandbyHrs = 0
dOOLHrs = 0
dOT_CTEHrs = 0
End If
End Sub
*自定义数据绑定事件:
'Fill DataGrid, dgdEmpSumHours
Sub dgdEmpSumHours_BindData()
Try
'connection
Using cn As SqlConnection = New SqlConnection(cStr)
'open connection
cn.Open()
'command
Dim cmd As SqlClient.SqlCommand = New SqlClient.SqlCommand("storedprocedurename", conn)
cmd.CommandType = CommandType.StoredProcedure
'pass input parameter
cmd.Parameters.Add("@EmpName", SqlDbType.VarChar).Value = ddwnEmpList.SelectedValue
cmd.Parameters.Add("@BStartDate", SqlDbType.VarChar).Value = PayPeriodBegDate()
cmd.Parameters.Add("@StopDate", SqlDbType.VarChar).Value = PayPeriodEndDate()
'execute(Query)
Dim reader As System.Data.SqlClient.SqlDataReader = cmd.ExecuteReader(CommandBehavior.CloseConnection)
dgdEmpSumHours.DataSource = reader
If (reader.HasRows) Then
Do While (reader.Read())
If IsDBNull(reader.Item("HOURS")) Then
dSumHours = 0
Else
dSumHours += reader.Item("HOURS")
End If
'
If IsDBNull(reader.Item("SBY")) Then
dStandbyHrs = 0
Else
dStandbyHrs += reader.Item("SBY")
End If
'
If IsDBNull(reader.Item("OTCT")) Then
dOT_CTEHrs = 0
Else
dOT_CTEHrs += reader.Item("OTCT")
End If
'
If IsDBNull(reader.Item("OOL")) Then
dOOLHrs = 0
Else
dOOLHrs += reader.Item("OOL")
End If
Loop
Else
ScriptManager.RegisterClientScriptBlock(Me, GetType(Page), "showalert", "alert('Oops, there is a problem displaying Summary of Hours table')", True)
End If
dgdEmpSumHours.DataBind()
End Using
Catch ex As System.Data.SqlClient.SqlException
'message about exception here
ScriptManager.RegisterClientScriptBlock(Me, GetType(Page), "script", "alert('A SQL Exception occurred: ' + ex.Message + '.')", True)
End Try
End Sub
免责声明:此版本的代码中可能存在拼写错误,这是我对它进行通用化的努力。它在我的环境中正常工作。