ในการดึงข้อมูลมาแสดงผลในรูปแบบตาราง GridView อาจเป็นหนึ่งในทางเลือกของนักพัฒนาที่จะหยิบไปใช้เป็นเครื่องมือในการแสดงผล แต่ในกรณีที่ข้อมูลมีจำนวนมากอาจทำให้ผู้ใช้รู้สึกตาลายและอ่านยากไปสักหน่อย ผู้พัฒนาจึงต้องพยายามหาวิธีจัดการข้อมูลในการแสดงผลให้สามารถอ่านง่ายและสบายตามากยิ่งขึ้น ดังนั้น ในกรณีที่ข้อมูลมีจำนวนมาก การจำแนกประเภท หรือแยกออกเป็นกลุ่มย่อยๆก็เป็นอีกหนึ่งในทางเลือกที่จะช่วยแก้ปัญหาดังกล่าวได้ ดังนั้น ในบทความนี้ผู้เขียนจะขอแนะนำวิธีการแสดงผลของข้อมูลบน GridView แบบจำแนกออกตามกลุ่ม เพื่ออำนวยความสะดวกให้กับผู้ใช้ในการดูข้อมูลแยกส่วนกัน เพื่อเพิ่มความสามารถให้กับ GridView ซึ่งเราเองใช้งานอยู่และน่าจะคุ้นเคยกันดีอยู่แล้ว ซึ่งจะมีขั้นตอนดังนี้ค่ะ
ขั้นตอนในการพัฒนา
- เตรียมข้อมูลในการแสดงผล โดยจากตัวอย่างนี้ จะทำการสมมุติข้อมูลของดอกไม้ ผลไม้ และต้นไม้ และมีข้อมูลเพื่อใช้ในการแยกประเภทไว้ด้วย เพื่อให้เห็นภาพมากขึ้นค่ะ
//// ประกาศตัวแปร GroupData
เป็น ViewState เพื่อใช้ในงานข้อมูลในส่วนการแทรกแถวประเภทกลุ่มใน Event อื่นด้วย
public DataTable GroupData
{
get
{
if (ViewState["GroupData"] == null)
{
ViewState["GroupData"] = new DataTable();
}
return (DataTable)ViewState["GroupData"];
}
set { ViewState["GroupData"] = value; }
}
//// ผู้อ่านสามารถเรียกใช้ฟังก์ชั่น Getdata() การดึงข้อมูลนี้ในตอน Page_Load เพื่อดูเป็นตัวอย่างได้ค่ะ
protected void Getdata()
{
GroupData.Columns.AddRange(new DataColumn[5] {
new DataColumn("CategoryName", typeof(string)),
new DataColumn("Name", typeof(string)),
new DataColumn("ID", typeof(string)),
new DataColumn("Amt", typeof(int)),
new DataColumn("CategoryID",typeof(string))});
GroupData.Rows.Add("Flower", "Rose", "1",2500, "01");
GroupData.Rows.Add("Flower", "Lotus", "3",150, "01");
GroupData.Rows.Add("Fruit", "Grape", "2",350, "02");
GroupData.Rows.Add("Fruit", "Mango", "4",1750, "02");
GroupData.Rows.Add("Fruit", "Orange", "5",2240, "02");
GroupData.Rows.Add("Tree", "Cactus", "6",370, "03");
GroupData.Rows.Add("Tree", "Hazelnut Tree", "6",2250, "03");
////นำข้อมูลใน Datatable ชื่อ GroupData แสดงผลใน GridView
GroupGv.DataSource = GroupData;
GroupGv.DataBind();
}
หมายเหตุ : การประกาศตัวแปร และการดึงข้อมูลเป็นเพียงการยกตัวอย่างง่ายๆ เพื่อให้ผู้ใช้เข้าใจเท่านั้น ในการทำงานจริงผู้อ่านสามารถใช้วิธีการประกาศตัวแปรและเรียกใช้แบบอื่น หรือดึงข้อมูลจากส่วนอื่นได้ ขึ้นอยู่กับความเหมาะสมและความถนัดค่ะ
2. เตรียม GridView ที่จะใช้ในการแสดงผล โดยจะขอยกตัวอย่างให้ดูการแสดงผล GridView แบบทั่วไปก่อนมีการจัดกลุ่ม เพื่อให้เห็นความแตกต่าง ดังนี้ค่ะ
<asp:GridView ID="GroupGv" runat="server" AutoGenerateColumns="False"
DataKeyNames="ID" CssClass="table table-sm table-hover Blue" Width="100%">
<AlternatingRowStyle CssClass="Blue" />
<EmptyDataRowStyle CssClass="Blue" />
<EmptyDataTemplate>
<br />
<div style="text-align: center">
<i class="fas fa-exclamation-circle"></i> ไม่พบข้อมูล<br />
</div>
</EmptyDataTemplate>
<EmptyDataRowStyle HorizontalAlign="Center" />
<HeaderStyle CssClass="Blue" />
<Columns>
<asp:TemplateField HeaderText="Name">
<ItemTemplate>
<asp:HiddenField ID="hdCatID" runat="server" Value='<%# Eval("CategoryID") %>' />
<asp:HiddenField ID="hdID" runat="server" Value='<%# Eval("ID") %>' />
<asp:HiddenField ID="HidCatName" runat="server" Value='<%# Eval("CategoryName") %>' />
<asp:Label ID="lblName" runat="server" Text='<%# Eval("Name") %>'></asp:Label>
</ItemTemplate>
<ItemStyle Width="50%" />
</asp:TemplateField> <asp:BoundField HeaderText="Category Name" DataField="CategoryName">
<ItemStyle Width="30%"/>
</asp:BoundField>
<asp:BoundField HeaderText="Amount" DataField="Amt" DataFormatString="{0:#,##0}" >
<ItemStyle HorizontalAlign="Right" Width="20%"/>
</asp:BoundField>
</Columns>
</asp:GridView>
เพิ่มเติม : ข้อมูลจำนวนเป็นข้อมูลที่เป็นตัวเลข จึงได้ทำการจัด Format รูปแบบของข้อมูลให้แสดงผลแบบตัวเลข ด้วยการระบุ DataFormatString=”{0:#,##0}” เช่น หากข้อมูล 2500 จะแสดง 2,500 ให้อัตโนมัติ
ผลลัพธ์(ก่อนทำการจัดกลุ่ม)
3. เพิ่ม Event ที่ชื่อว่า OnDataBound=”GroupGv_DataBound” ให้กับ GridView เพื่อแสดงผลข้อมูลแบบกลุ่ม และตัดคอลัมน์ประเภท(Category Name)ออกไป เนื่องจากเราจะนำไปใช้แสดงผลในการจัดกลุ่ม
<asp:GridView ID="GroupGv" runat="server" AutoGenerateColumns="False"
DataKeyNames="ID" CssClass="table table-sm table-hover Blue" Width="100%" OnDataBound="GroupGv_DataBound">
<AlternatingRowStyle CssClass="Blue" />
<EmptyDataRowStyle CssClass="Blue" />
<EmptyDataTemplate>
<br />
<div style="text-align: center">
<i class="fas fa-exclamation-circle"></i> ไม่พบข้อมูล<br />
</div>
</EmptyDataTemplate>
<EmptyDataRowStyle HorizontalAlign="Center" />
<HeaderStyle CssClass="Blue" />
<Columns>
<asp:TemplateField HeaderText="Name">
<ItemTemplate>
<%--นำค่าไปใช้ตอนแทรกแถวหมวดหมู่ที่ต้องการจัดกลุ่ม--%>
<asp:HiddenField ID="hdCatID" runat="server" Value='<%# Eval("CategoryID") %>' />
<asp:HiddenField ID="hdID" runat="server" Value='<%# Eval("ID") %>' />
<asp:HiddenField ID="HidCatName" runat="server" Value='<%# Eval("CategoryName") %>' />
<asp:Label ID="lblName" runat="server" Text='<%# Eval("Name") %>'></asp:Label>
</ItemTemplate>
<ItemStyle Width="70%" />
</asp:TemplateField>
<asp:BoundField HeaderText="Amount" DataField="Amt" DataFormatString="{0:#,##0}">
<ItemStyle HorizontalAlign="Right" Width="30%"/>
</asp:BoundField>
</Columns>
</asp:GridView>
4. เพิ่มโค้ดในส่วนของฝั่งเซิร์ฟเวอร์(C#) ให้กับ Event ของ GridView ที่เราเพิ่มในข้อ 3. เพื่อจัดกลุ่ม ดังนี้ค่ะ
string lastCatName = "";
string AllName = "";
protected void GroupGv_DataBound(object sender, EventArgs e)
{
lastCatName = "";
Table table = (Table)GroupGv.Controls[0];
////////วนเพื่อแทรกแถวชื่อแต่ละประเภทของข้อมูล เช่น ดอกไม้ ต้นไม้ หรือผลไม้
foreach (GridViewRow row in GroupGv.Rows)
{
HiddenField HidCatName = (HiddenField)row.FindControl("HidCatName");
HiddenField HidCatID = (HiddenField)row.FindControl("hdCatID");
HiddenField HidID = (HiddenField)row.FindControl("hdID");
////////หากพบว่าเป็นประเภทใหม่จะทำการสร้างแถวและเพิ่มแทรกเข้าไป โดยมีการกำหนดค่าต่างๆ เช่น ข้อความที่จะแสดง สีพื้นหลัง สีตัวอักษร และค่า ColumnSpan เป็นต้น
if (HidCatName.Value != lastCatName)
{
int realIndex = table.Rows.GetRowIndex(row);
string text = HidCatName.Value;
GridViewRow newHeaderRow = new GridViewRow(realIndex, 0, DataControlRowType.Header, DataControlRowState.Normal);
/////สร้าง TableCell และระบุค่าต่างๆ ก่อนนำไปเพิ่มในแถว newHeaderRow ที่เพิ่งสร้าง
TableCell newCell = new TableCell();
newHeaderRow.Cells.AddAt(0, newCell);
///กำหนด ColumnSpan เท่ากับจำนวนคอลัมน์ทั้งหมดใน GridView (GroupGv.Columns.Count)เพื่อให้คอลัมน์ที่ต้องการเพิ่มยาวครอบคลุมทั้งแถว
newCell.ColumnSpan = GroupGv.Columns.Count;
newCell.BackColor = System.Drawing.Color.FromName("#399ea9"); ;
newCell.ForeColor = System.Drawing.Color.White;
newCell.Font.Bold = true;
newCell.Text = string.Format(HidCatName.Value, " {0}", text);
////เพิ่มแถวที่ต้องการแทรกเข้าไปในตารางหรือ GridView ที่เรากำลังจัดการอยู่นั่นเอง
table.Controls.AddAt(realIndex, newHeaderRow);
}
lastCatName = HidCatName.Value;
}
}
ผลลัพธ์ (หลังมีการจัดกลุ่ม)
เพิ่มเติม : จากตัวอย่างข้างต้น เนื่องด้วยข้อมูลเป็นการจัดกลุ่มและมีข้อมูลเชิงตัวเลข ผู้เขียนจึงขอแนะนำเพิ่มเติมในส่วนของการแสดงจำนวนรวมแยกในแต่ละกลุ่มไว้ด้วย โดยเพิ่มเติมโค้ดในส่วนของ GroupGv_DataBound ดังนี้ค่ะ
protected void GroupGv_DataBound(object sender, EventArgs e)
{
lastCatName = "";
Table table = (Table)GroupGv.Controls[0];
foreach (GridViewRow row in GroupGv.Rows)
{
HiddenField HidCatName = (HiddenField)row.FindControl("HidCatName");
HiddenField HidCatID = (HiddenField)row.FindControl("hdCatID");
HiddenField HidID = (HiddenField)row.FindControl("hdID");
if (HidCatName.Value != lastCatName)
{
//// เป็นการหาผลรวมค่าของฟิลด์ Amt ซึ่งหมายถึงจำนวน โดยเป็นการรวมค่าฟิลด์แยกตามแต่ละ CategoryID นั่นเอง
var sumOfValuesInCategory = GroupData.AsEnumerable().Where(x => x.Field<string>("CategoryID") == HidCatID.Value).Sum(x => x.Field<int>("Amt")).ToString();
int realIndex = table.Rows.GetRowIndex(row);
string text = HidCatName.Value;
GridViewRow newHeaderRow = new GridViewRow(realIndex, 0, DataControlRowType.Header, DataControlRowState.Normal);
TableCell newCell = new TableCell();
newHeaderRow.Cells.AddAt(0, newCell);
/////ปรับแก้การระบุค่า ColumnSpan จากเดิมที่รวมกันทุกคอลัมน์(GroupGv.Columns.Count)
//// แต่กรณีนี้ต้องเว้นคอลัมน์ไว้แสดงผลจำนวนรวมแต่ละประเภทด้วย
newCell.ColumnSpan =1;
newCell.BackColor = System.Drawing.Color.FromName("#399ea9"); ;
newCell.ForeColor = System.Drawing.Color.White;
newCell.Font.Bold = true;
newCell.Text = string.Format(HidCatName.Value, " {0}", text);
///สร้าง TableCell หรือคอลัมน์ใหม่ เพื่อแสดงผลข้อมูลจำนวนรวมของแต่ละประเภท
TableCell newCellTotal = new TableCell();
/////เพิ่ม TableCell ในแถวที่กำลังสร้างและระบุค่าต่างๆ
newHeaderRow.Cells.AddAt(1, newCellTotal);
newCellTotal.ColumnSpan = 1;
newCellTotal.BackColor = System.Drawing.Color.FromName("#399ea9"); ;
newCellTotal.ForeColor = System.Drawing.Color.White;
newCellTotal.Font.Bold = true;
newCellTotal.HorizontalAlign = HorizontalAlign.Right;
////นำค่าผลรวมในตัวแปร sumOfValuesInCategory ที่คำนวณได้ข้างต้นมาจัดรูปแบบก่อนแสดงผลใน TableCell สร้าง
newCellTotal.Text = string.Format("{0:#,##0}",int.Parse(sumOfValuesInCategory));
table.Controls.AddAt(realIndex, newHeaderRow);
}
lastCatName = HidCatName.Value;
}
}
ผลลัพธ์
เพียงเท่านี้ท่านก็จะสามารถจัดกลุ่มข้อมูล GridView ของท่าน เพื่อลดปัญหาการดูข้อมูลแบบตารางที่มีแถวข้อมูลจำนวนมากได้บ้างแล้ว ซึ่งผู้เขียนหวังเป็นอย่างยิ่งว่าผู้อ่านจะสามารถนำแนวทาง เกร็ดเล็กๆน้อยๆนี้ไปประยุกต์ใช้กับงานของท่านได้ไม่มากก็น้อยนะคะ หากมีส่วนใดผิดพลาดทางผู้เขียนก็ขออภัยมา ณ ที่นี้ด้วยค่ะ ขอบคุณที่ติดตามนะคะ ^^
แหล่งอ้างอิง
https://stackoverflow.com/questions/61773421/sum-column-where-condition-with-datatable