จากความเดิมตอนที่แล้ว เราได้พูดถึงวิธีการจัดการข้อมูลจำนวนมากด้วยการจัดกลุ่มหมวดหมู่ของข้อมูลใน GridView กันไปแล้ว ซึ่งหากผู้อ่านท่านใดต้องการทราบวิธีการจัดหมวดหมู่สามารถตามดูเนื้อหาในบทความได้จาก การจัดหมวดหมู่แถวของข้อมูลบน GridView ด้วย C# และในส่วนของบทความนี้จะเป็นเนื้อหาต่อยอดการทำงานจากการจัดหมวดหมู่ดังกล่าว โดยเพิ่มความสามารถให้หมวดหมู่หรือกลุ่มเหล่านั้นสามารถย่อ-ยุบได้ เพื่ออำนวยความสะดวกให้กับผู้ใช้ในการดูข้อมูลแยกส่วนกันชัดเจนมากยิ่งขึ้น หรือเพื่อตอบโจทย์ให้กับผู้ใช้บางท่านที่อาจมีความต้องการดูข้อมูลทีละส่วนได้ โดยจะนำ Component ที่ชื่อว่า Collapse ใน Bootstrap มาประยุกต์ใช้ในการแสดงผลร่วมกับ GridView และยังมี jQuery มาเป็นอีกหนึ่งตัวช่วยเพื่อให้สามารถแสดงผลตามที่ต้องการได้ โดยการอธิบายในบทความนี้ ทางผู้เขียนจะขอตัดตอนในส่วนของรายละเอียดขั้นตอนวิธีการจัดหมวดหมู่ไป และข้ามมาพูดถึงขั้นตอนที่ต้องจัดทำเพิ่มเติมในการทำย่อ-ยุบเลยละกันนะคะ
ก่อนจะไปเริ่มในส่วนของการเขียนโค้ด เรามาทำความรู้จักกับ ค่าที่จำเป็นต้องใช้ในการระบุให้กับแถวหลัก(parent)เพื่อให้สามารถย่อยุบได้ กันก่อนนะคะ
- data-toggle=”collapse”
- data-target=”.multi-collapse” เพื่อกำหนด target ที่เราต้องการให้ย่อยุบได้ โดยใช้สไตล์ชีทเป็นตัวช่วยเพื่อแยกแต่ละกลุ่มออกจากกัน ซึ่งในที่นี้จะตั้งชื่อสไตล์ชีท multi-collapse ตามด้วยรหัสของประเภทกลุ่มนั้น โดยต้องระบุสไตล์ชีทนี้ให้กับแถวย่อย(child)ด้วย
- aria-controls=”demo1 demo2 demo3 demo4 demo5” เพื่อกำหนดพื้นที่ที่จะย่อยุบ โดยสามารถกำหนดได้มากกว่า 1 พื้นที่ ซึ่งจะแยกด้วยการเว้นวรรคชื่อ id ของแถวย่อย(child) ในตัวอย่างนี้ คือ แถวย่อยของแถวหลักนี้ ประกอบด้วย 5 แถว คือ แถวที่มี id ชื่อ demo1,demo2,demo3,demo4, demo5 นั่นเอง
- class = “collapseToggle” เป็นการระบุสไตล์ชีทเพื่อใช้ในการระบุตำแหน่งในการเปลี่ยนไอคอนเวลากดย่อ-ยุบ โดยเรียกใช้งานผ่าน jQuery(ซึ่งจะกล่าวถึงในส่วนถัดไป)
หลังจากเรารู้จักค่าที่จำเป็นต้องใช้กันไปแล้ว เราก็มาเริ่มปรับแก้โค้ดเพิ่มเติม เพื่อเพิ่มความสามารถให้ GridView ของเรากันเลยค่ะ
1. ปรับแก้ในส่วนของ GroupGv_DataBound เพิ่มเติม เพื่อกำหนดค่าที่ระบุไว้ข้างต้นในแถวของหมวดหมู่ที่แทรกเข้ามา
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");
////ตั้งชื่อ id ให้กับแถวย่อย(child) แต่ละแถว
row.Attributes.Add("id", "Name" + HidID.Value);
////กำนดสไตล์ชีทของตัวแถวย่อยและระบุเพื่อให้ย่อยุบได้ ด้วย accordian-body collapse และระบุพื้นที่เพื่อให้อ้างถึงจากแถวหลัก(parent)ได้
/////ซึ่งเป็นในส่วนของ multi-collapse จะเป็น multi-collapse ตามด้วยชื่อรหัสประเภทนั่นเอง
/////โดยแถวย่อย(child) ที่มีแถวหลัก(parent)เดียวกัน ค่าของ multi-collapse จะตรงกันและตรงกับค่า target ที่ระบุไว้ในแถวหลัก(parent)ด้วย
if (row.RowState == DataControlRowState.Alternate) ////กรณีที่ต้องการให้แต่ละแถวสลับสีกันเพื่อให้ง่ายต่อการดูข้อมูล
row.CssClass = "Blue accordian-body collapse multi-collapse" + HidCatID.Value;
else
row.CssClass = "accordian-body collapse multi-collapse" + HidCatID.Value;
if (HidCatName.Value != lastCatName)
{
////////วนเพื่อหาจำนวน child ในแต่ละประเภทเพื่อใช้ในการกำหนด aria-controls
var strList = GroupData.Select("CategoryID='" + HidCatID.Value + "'");
foreach (DataRow dr in strList)
{
AllName += " Name" + dr["ID"];
}
//// เป็นการหาผลรวมค่าของฟิลด์ 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);
/////กำหนดค่าต่างๆ (data-toggle data-target aria-controls )ให้กับแถว เพื่อให้สามารถย่อ-ยุบได้
newHeaderRow.Attributes.Add("data-toggle", "collapse");
newHeaderRow.Attributes.Add("data-target", ".multi-collapse" + HidCatID.Value);
newHeaderRow.Attributes.Add("aria-expanded", "true");
newHeaderRow.Attributes.Add("aria-controls", AllName);
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.Attributes.Add("class", "collapseToggle");
/////ใส่ไอคอน + หน้าข้อความชื่อประเภท เพื่อบอกให้ทราบว่าสามารถกดย่อ-ยุบได้
newCell.Text = "<i class='fas fa-plus mr-2'></i>" + 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));
newCellTotal.Attributes.Add("class", "collapseToggle");
table.Controls.AddAt(realIndex, newHeaderRow);
AllName = "";
}
lastCatName = HidCatName.Value;
}
}
2.จัดทำให้ไอคอนสามารถเปลี่ยนเป็น + หรือ – ได้ เมื่อกดย่อ-ยุบ ด้วย jQuery
<script>
$(document).ready(function () {
///เมื่อมีการคลิก element ที่มีสไตล์ชีท collapseToggle จะทำการเปลี่ยนค่าไอคอน หากเป็นภาพบวกจะเปลี่ยนเป็นลบ หากเป็นเครื่องหมายลบจะเปลี่ยนเป็นเครื่องหมายบวก
$('.collapseToggle').click(function () {
$(this).find('i').toggleClass('fa-plus fa-minus');
});
});
</script>
เพิ่มเติม : ท่านสามารถสร้างสไตล์ชีทตกแต่งเพิ่มเติมให้กับแถวของข้อมูลได้ ในกรณีนี้ได้ทำการสร้างสไตล์ชีทเพื่อไว้สำหรับเวลาเอาเม้าส์ชี้ที่แถวที่สามารถย่อ-ยุบได้ จะแสดงเป็นรูปมือ เพื่อให้ผู้ใช้ทราบว่าสามารถกดได้ค่ะ
<style>
.collapseToggle {
cursor: pointer;
}
</style>
ผลลัพธ์
เกร็ดความรู้เพิ่มเติม : จากตัวอย่างข้างต้น ตอนเปิดหน้าจอครั้งแรก ทุกหมวดหมู่จะถูกยุบอยู่ หากต้องการให้การแสดงผลครั้งแรก ทุกหมวดหมู่ถูกขยายอยู่ สามารถปรับแก้โค้ดอีกเพียงเล็กน้อย ดังนี้ค่ะ
- เพิ่มคำว่า “show” เข้าไปในสไตล์ชีทตอนกำหนดให้แถวย่อย ดังนี้ค่ะ
แบบเดิม
if (row.RowState == DataControlRowState.Alternate) ////กรณีที่ต้องการให้แต่ละแถวสลับสีกันเพื่อให้ง่ายต่อการดูข้อมูล
row.CssClass = "Blue accordian-body collapse multi-collapse" + HidCatID.Value;
else
row.CssClass = "accordian-body collapse multi-collapse" + HidCatID.Value;
แบบใหม่
if (row.RowState == DataControlRowState.Alternate) ////กรณีที่ต้องการให้แต่ละแถวสลับสีกันเพื่อให้ง่ายต่อการดูข้อมูล
row.CssClass = "Blue accordian-body collapse show multi-collapse" + HidCatID.Value;
else
row.CssClass = "accordian-body collapse show multi-collapse" + HidCatID.Value;
2.ปรับแก้ให้ไอคอนแรกที่ต้องการแสดงเป็นเครื่องหมายลบ ดังนี้ค่ะ
แบบเดิม
/////ใส่ไอคอน + หน้าข้อความชื่อประเภท เพื่อบอกให้ทราบว่าสามารถกดย่อ-ยุบได้
newCell.Text = "<i class='fas fa-plus mr-2'></i>" + string.Format(HidCatName.Value, " {0}", text);
แบบใหม่
/////ใส่ไอคอน + หน้าข้อความชื่อประเภท เพื่อบอกให้ทราบว่าสามารถกดย่อ-ยุบได้
newCell.Text = "<i class='fas fa-minus mr-2'></i>" + string.Format(HidCatName.Value, " {0}", text);
ผลลัพธ์
จากตัวอย่าง การแสดงผลครั้งแรกก็จะเปลี่ยนเป็นขยายทั้งหมด และแสดงไอคอนเป็นเครื่องหมายลบ(-)ตั้งต้นไว้ให้ และสามารถย่อ-ยุบตามปกติได้แล้วค่ะ
เพิ่มเติม
นอกจากนี้ ผู้เขียนขอแถมให้อีกนิดสำหรับท่านที่ต้องการจะย่อประเภทกลุ่มทั้งหมด หรือต้องการให้แสดงประเภทกลุ่มทั้งหมด อาจจะทำเป็นปุ่มให้ผู้ใช้กด ซึ่งมีวิธี ดังนี้ค่ะ
1. สร้างปุ่ม 2 ปุ่ม เพื่อกดขยายทั้งหมด และย่อทั้งหมด
<asp:UpdatePanel ID="UpdatePanel1" runat="server">
<ContentTemplate>
<div class="col pull-right">
<asp:LinkButton ID="lnkShowAll" runat="server" CssClass="btn btn-sm btn-info mb-1" OnClientClick="javascript:ShowHideAll('1');return false;"><i class="fas fa-eye"></i>แสดงทั้งหมด</asp:LinkButton>
<asp:LinkButton ID="lnkHideAll" CssClass="btn btn-sm btn-info mb-1" OnClientClick="ShowHideAll('0');return false;" runat="server"><i class="fas fa-eye-slash"></i>ซ่อนทั้งหมด</asp:LinkButton>
</div>
</ContentTemplate>
</asp:UpdatePanel>
2. เขียนฟังก์ชั่นในการซ่อน/แสดงทั้งหมด
<script>
function ShowHideAll(flag) {
/////ล้างค่าการระบุการแสดงผลและการแสดงไอคอนทั้งหมด ทำให้ทุกแถวยุบอยู่ จนกว่าจะมีการสั่งให้ show
$(".accordian-body").removeClass("show");
$(".collapseToggle").find('i').removeClass("fa-plus").removeClass("fa-minus");
/////กรณีต้องการให้แสดงจะเพิ่มสไตล์ชีท show ให้กับทุกแถว และแสดงไอคอนเป็น - ทั้งหมด เพื่อให้กดย่อได้
if (flag == '1') {
$(".accordian-body").addClass("show");
$(".collapseToggle").find('i').addClass("fa-minus");
}
/////กรณีต้องการให้แสดงจะแสดงไอคอนเป็น + ทั้งหมด เพื่อให้กดขยายได้
else
$(".collapseToggle").find('i').addClass("fa-plus");
}
</script>
ผลลัพธ์
หมายเหตุ : ในการทำงานนี้จะใช้ jQuery และ Bootstrap ร่วมด้วย ผู้ที่จะนำไปใช้งานอย่าลืมอ้างอิงไฟล์สไตล์ชีทและสคริปท์ของ Bootstrap รวมทั้งไฟล์ของ jQuery เพื่อให้โค้ดข้างต้นสามารถทำงานได้นะคะ
ทั้งหมดนี้ก็เป็นเพียงหนึ่งในตัวอย่างวิธีการที่จะแก้ปัญหาในการแสดงผลข้อมูลแบบตารางด้วย GridView แบบจัดกลุ่มและสามารถย่อ-ยุบข้อมูลภายในกลุ่มได้ โดยนำความสามารถของ Component อย่าง collapse ใน Bootstrap เข้ามาช่วยเท่านั้น แต่ในส่วนของรูปแบบ วิธีการ แต่ละท่านสามารถปรับเปลี่ยนและพลิกแพลงเพิ่มเติมได้ตามความเหมาะสม อีกทั้งยังสามารถนำเกร็ดความรู้นี้ไปประยุกต์ใช้กับงานของท่านได้อีกด้วย และขอบคุณที่ติดตามนะคะ ^^
แหล่งอ้างอิง
https://getbootstrap.com/docs/4.0/components/collapse/
https://www.geeksforgeeks.org/how-to-change-symbol-with-a-button-in-bootstrap-accordion/