อยากดึงข้อมูลมาแสดงใน TreeView จะทำอย่างไรดี?

          ในบทความนี้ ผู้เขียนก็ยังคงอยู่ในเรื่องของ TreeView เช่นเคย เพื่อต่อยอดจากบทความก่อนในหัวข้อเรื่อง “มาทำความรู้จักกับพื้นฐานการใช้งาน “TreeView” สำหรับมือใหม่กันดีกว่า” ที่เป็นบทความเกี่ยวกับเรื่องการแนะนำวิธีจัดการกับ TreeView ด้วยการกำหนดคุณสมบัติต่างๆ แต่งสีเติมกลิ่น ให้ TreeView ของเราน่าสนใจยิ่งขึ้น แต่ข้อมูลที่นำมาใช้ในการแสดงผลยังคงเป็นในลักษณะกำหนดเองเป็นค่าตายตัวจากหน้าจอและยังไม่เน้นเรื่องดึงข้อมูลจากฐานข้อมูล ในบทความนี้จึงถือเป็นภาคต่อจากบทความที่แล้วและขอเน้นในส่วนของการดึงข้อมูลมาแสดงผลบน TreeView ในเชิงโปรแกรมกันบ้าง เพื่อให้ผู้อ่านได้ความรู้ทั้งในส่วนการกำหนดคุณสมบัติและการดึงข้อมูลมาแสดงไปประยุกต์ใช้ในงานพัฒนาร่วมกันได้

ขั้นตอนในการดึงข้อมูลจากฐานข้อมูลมาแสดงใน TreeView

  1. สร้าง TreeView ที่ต้องการใช้ในการแสดงผลข้อมูล
    ตัวอย่าง code ในฝั่ง Client
    <body>
    <form id="form1" runat="server">
    <asp:TreeView ID="TvOrganization" runat="server" >
    </asp:TreeView>
    </form>
    </body>
  2. ติดต่อฐานข้อมูลเพื่อใช้ในการแสดงผล ซึ่งในตัวอย่างนี้จะขอสมมุติข้อมูลจาก datatable ที่สร้างขึ้นแทน
    ตัวอย่าง code ในฝั่ง Server (C#)
    • ฟังก์ชั่นตอน Page_Load
    protected void Page_Load(object sender, EventArgs e)
        {
            if (!this.IsPostBack)
            {   ///////ดึงข้อมูลวิทยาเขต โดยในการใช้งานจริงจะเป็นการติดต่อกับฐานข้อมูลเพื่อดึงค่าวิทยาเขตมาแสดง
                DataTable dt = this.GetCampusData();
            
    ///////เรียกใช้งานฟังก์ชั่น PopulateTreeView() เพื่อนำค่าข้อมูลวิทยาเขตมาแสดงผลใน TreeView 
    โดยในกรณีนี้จะเริ่มสร้างจาก root node โดยส่งค่าพารามิเตอร์ของ parentId เป็น 0
                this.PopulateTreeView(dt, 0, null);
            }
        }
    • ฟังก์ชั่นดึงข้อมูลวิทยาเขตและคณะ/หน่วยงาน
    private DataTable GetCampusData() {
     ///////เตรียมข้อมูลวิทยาเขต เนื่องจากในกรณีนี้เป็นการสมมุติโครงสร้างและข้อมูลวิทยาเขตโดยสร้างเป็น DataTable 
    เสมือนเป็นตารางวิทยาเขตในฐานข้อมูล
    DataTable dtCampus = new DataTable();
    dtCampus.Columns.AddRange(new DataColumn[2] {
    new DataColumn("CampID", typeof(int)), 
    new DataColumn("CampNameThai",typeof(string)) }); 
    dtCampus.Rows.Add("01", "วิทยาเขตหาดใหญ่"); 
    dtCampus.Rows.Add("02", "วิทยาเขตปัตตานี");
    dtCampus.Rows.Add("03", "วิทยาเขตภูเก็ต"); 
    dtCampus.Rows.Add("04", "วิทยาเขตสุราษฎร์ธานี");
    dtCampus.Rows.Add("05", "วิทยาเขตตรัง"); return dtCampus; } private DataTable GetFacultyData() { ///////เตรียมข้อมูลคณะ/หน่วยงาน ในกรณีนี้เป็นการสมมุติโครงสร้างข้อมูลคณะ/หน่วยงานและสร้างเป็น DataTable โดยมีการระบุรหัสของวิทยาเขตไว้ด้วย ซึ่งในการทำงานจริงจะเป็นการดึงข้อมูลจากตารางที่เก็บข้อมูลคณะ/หน่วยงานแทน DataTable dtFaculty = new DataTable(); dtFaculty.Columns.AddRange(new DataColumn[3] { new DataColumn("FacID", typeof(int)), new DataColumn("FacNameThai",typeof(string)) , new DataColumn("CampID",typeof(string)) }); dtFaculty.Rows.Add("01", "สำนักงานอธิการบดี","01"); dtFaculty.Rows.Add("02", "ศูนย์คอมพิวเตอร์", "01"); dtFaculty.Rows.Add("03", "วิศวกรรมศาสตร์", "01"); dtFaculty.Rows.Add("54", "คณะรัฐศาสตร์", "02"); dtFaculty.Rows.Add("07", "ศึกษาศาสตร์", "02"); dtFaculty.Rows.Add("36", "วิทยาการสื่อสาร", "02"); dtFaculty.Rows.Add("81", "ศูนย์การเรียนรู้", "03"); dtFaculty.Rows.Add("56", "คณะศิลปศาสตร์และวิทยาศาสตร์", "04"); dtFaculty.Rows.Add("44", "คณะเทคโนโลยีและการจัดการ", "04"); dtFaculty.Rows.Add("46", "คณะพาณิชยศาสตร์และการจัดการ", "05"); dtFaculty.Rows.Add("66", "คณะสถาปัตยกรรมศาสตร์", "05"); return dtFaculty; }
    • ฟังก์ชั่นที่ใช้ในการวนแสดงข้อมูลที่ได้จากวิทยาเขตและคณะ/หน่วยงานมาแสดงใน TreeView
    private void PopulateTreeView(DataTable dtParent, int parentId, TreeNode treeNode)
    {
    ///////ดึงค่าข้อมูลคณะ/หน่วยงาน
    DataTable dtChild = this.GetFacultyData();
    DataRow[] drChild;
    
    ///////วนค่าข้อมูลวิทยาเขตจาก dtParent ที่เป็นพารามิเตอร์ที่ส่งมา
    foreach (DataRow row in dtParent.Rows)
    {
    
    if (parentId == 0) ///////กรณีที่เป็น root node ค่าของ parentId จะเท่ากับ 0 ซึ่งในที่นี้หมายถึง node วิทยาเขต นั่นเอง
    {
       TreeNode child = new TreeNode
      {  ///////กำหนดคุณสมบัติให้กับ root node ในส่วนของ Text,Value,ToolTip,SelectAction ตอน runtime 
    ขึ้นอยู่กับเงื่อนไขและจุดประสงค์ที่เราต้องการให้แสดงผล โดยในที่นี้จะนำค่าข้อมูลจากวิทยาเขตมาวนแสดง
    
    ///////สามารถกำหนด Style ตอนระบุ Text ได้ด้วย โดยในกรณีนี้ใส่ style ในแท็ก <span></span> นั่นเอง
        Text = "<span style='color:blue;font-weight:bold'>" + row["CampNameThai"].ToString() + "</span>" ,  
    
    ///////กำหนดค่าของ node เป็นรหัสวิทยาเขต
        Value = row["CampID"].ToString(),
    
    //////ระบุให้ ToolTip เป็นชื่อวิทยาเขต[รหัสวิทยาเขต]
        ToolTip = row["CampNameThai"].ToString() + "[" + row["CampID"].ToString() +"]", 
    
    ///////ระบุคุณสมบัติไม่ให้เลือกได้
        SelectAction = TreeNodeSelectAction.None, 
       };
    ///////เมื่อระบุคุณสมบัติและกำหนดค่าเรียบร้อยแล้วจะเพิ่ม node ดังกล่าวลงใน TreeView ที่ชื่อว่า TvOrganization
      TvOrganization.Nodes.Add(child); 
    
    ///////ดึงข้อมูลคณะ/หน่วยงานตามวิทยาเขตที่กำลังวนค่าซึ่งก็คือ row["CampID"].ToString()
      drChild = dtChild.Select("CampID=" + row["CampID"].ToString());
    
    ///////เรียกใช้ฟังก์ชั่น PopulateTreeView() โดยส่งค่าข้อมูลคณะ/หน่วยงานของวิทยาเขตที่กำลังวน(ตัวแปร drChild.CopyToDataTable())
    เพื่อวนสร้าง node ย่อยเพิ่มลงไปใน node วิทยาเขตที่กำลังจัดการ(ตัวแปร child)
    PopulateTreeView(drChild.CopyToDataTable(), int.Parse(child.Value), child); }
    else ///////กรณีที่เป็นการจัดการ node ย่อย ซึ่งในที่นี้หมายถึง node คณะ/หน่วยงาน { TreeNode child = new TreeNode { ///////กำหนดคุณสมบัติให้กับ node ย่อย
    ในส่วนของ Text,Value,ToolTip,SelectAction,ImageUrl,NavigateUrl,Target ตอน runtime ขึ้นอยู่กับเงื่อนไขและจุดประสงค์ที่เราต้องการให้แสดงผล โดยในที่นี้จะนำค่าข้อมูลจากคณะ/หน่วยงานมาวนแสดง
    ///////แสดงค่าข้อมูลคณะ/หน่วยงานที่กำลังวน Text = row["FacNameThai"].ToString() , ///////แสดงค่าข้อมูลรหัสคณะ/หน่วยงานที่กำลังวน Value = row["FacID"].ToString(), //////ระบุให้ ToolTip เป็นชื่อคณะ/หน่วยงาน[รหัสคณะ/หน่วยงาน] ToolTip = row["FacNameThai"].ToString() + "[" + row["FacID"].ToString() + "]", ///////ระบุคุณสมบัติไม่ให้สามารถคลิกเลือก node ได้ SelectAction = TreeNodeSelectAction.Select, ///////ระบุ url ของเพจที่ต้องการให้ลิงค์ไปโดยส่งค่าพารามิเตอร์ของรหัสคณะ/หน่วยงานไปด้วยกรณีที่ต้องการนำค่าข้อมูลไปใช้ต่อในเพจดังกล่าว NavigateUrl = "BasicTreeviewAll.aspx?FacId=" + row["FacID"].ToString(), ///////กำหนดให้เปิดเพจใหม่ Target="_blank", ///////กำหนดให้แสดงรูปภาพดาวหน้าข้อความใน node ดังกล่าว ImageUrl = "~/images/star.png", }; ///////เมื่อระบุคุณสมบัติและกำหนดค่าเรียบร้อยแล้วจะเพิ่ม node ดังกล่าวลงใน ตัวแปร treeNode(ซึ่งก็คือ node แม่ที่ถูกส่งมานั่นเอง) ซึ่งเป็นพารามิเตอร์ที่ส่งมาตอนเรียกใช้ฟังก์ชั่น PopulateTreeView() แต่ถ้าเป็นกรณี เรียกใช้ฟังก์ชั่นเพื่อสร้าง root node ค่า treeNode ที่ส่งมานี้จะเป็น null treeNode.ChildNodes.Add(child); } } }

    หมายเหตุ :
    1) การกำหนดคุณสมบัติให้กับ node ตอน RunTime เราสามารถเลือกระบุคุณสมบัติได้เช่นเดียวกับตอนกำหนดฝั่ง Client ที่เคยกล่าวไว้ในบทความก่อน โดย properties ที่สามารถระบุได้ขึ้นอยู่กับความต้องการของผู้ใช้ มีดังนี้

    2) การประยุกต์ใช้งานและการดึงข้อมูลที่จะนำมาวนแสดงสามารถปรับเปลี่ยนในแบบที่ท่านต้องการ เพื่อเพิ่มประสิทธิภาพในการทำงานของโปรแกรมให้รวดเร็วขึ้นได้ โดยกรณีนี้เพียงยกตัวอย่างเพื่อเน้นให้ดูการวนมาแสดงใน TreeView เท่านั้น

    ตัวอย่างแสดงผลลัพธ์ของการดึงข้อมูลมาแสดงใน TreeView จากโค้ดข้างต้น


          นอกจากนี้ ท่านยังสามารถเพิ่มความสามารถให้กับ TreeView ของท่านได้อีกหน่อยในกรณีที่ TreeView ที่ต้องการจัดการมี check box และต้องการให้สามารถเลือก node แม่และสามารถเลือก node ลูกทั้งหมดด้วยได้ (ลักษณะคล้ายกับแบบ Select All นั่นเอง) โดยใช้  jQuery เข้ามาช่วย โดยเพิ่ม code ที่เป็น jQuery  ดังนี้ ค่ะ

  1. อ้างอิงไฟล์ที่ใช้ในการทำงานร่วมกับ jQuery
    <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script>
  2. ส่วนของ jQuery ที่ใช้ในการเลือกแบบ Select All ให้กับ node แม่และลูก
    <script type="text/javascript">
        $(function () {
            $("[id*=TvOrganization] 
    ////ทุกครั้งที่คอนโทรลที่มีชนิดเป็น checkbox ถูกคลิก
    input[type=checkbox]").bind("click", function () {
    ////จะหา tag table ที่ใกล้ที่สุด เพื่อแยกระหว่าง node แม่(วิทยาเขต)และลูก(คณะ/หน่วยงาน)
                var table = $(this).closest("table");
                if (table.next().length > 0 && table.next()[0].tagName == "DIV") {
                  ////เป็นการตรวจสอบว่าเป็น node ที่เป็นแม่หรือไม่
    โดยตรวจสอบว่าต้องเจอแท็ก table ถัดไป และแท็ก table ดังกล่าวต้องมีแท็ก DIV อยู่ด้วย
    var childDiv = table.next();

    ////นำค่าการเช็คของ check box ดังกล่าว มาใส่ไว้ในตัวแปร isChecked var isChecked = $(this).is(":checked");

    ////นำค่าจากตัวแปร isChecked ไปเซ็ทการเช็คหรือไม่เช็คใน check box ใน node ลูกทั้งหมด $("input[type=checkbox]", childDiv).each(function () { if (isChecked) { $(this).attr("checked", "checked"); } else { $(this).removeAttr("checked"); } }); } else { ////กรณีที่เป็น node ย่อยหรือ node ลูก var parentDIV = $(this).closest("DIV");

     ////ถ้าค่าของจำนวน node ย่อย เท่ากับจำนวนของการเช็คใน node ย่อยจะไปเช็ค check box ตัวแม่ด้วย
    แต่ถ้าไม่เท่ากันจะไปติ๊กเลือกออกจาก check box ตัวแม่ให้อัตโนมัติ
    if ($("input[type=checkbox]", parentDIV).length ==
    $("input[type=checkbox]:checked", parentDIV).length)
    { $("input[type=checkbox]", parentDIV.prev()).attr("checked", "checked"); } else { $("input[type=checkbox]", parentDIV.prev()).removeAttr("checked"); } } }); }) </script>

    คำอธิบายเพิ่มเติม :
           จากโค้ดของ jQuery เบื้องต้น ที่มีการแยกระหว่างส่วนของ node แม่และลูก เนื่องจากเมื่อดูจากโครงสร้าง Tag HTML ของ TreeView ที่ถูกสร้างขึ้นเมื่อทำการรันโปรแกรมเพื่อแสดงผล จะสังเกตว่าจะมีการสร้างเป็น Tag HTML ในลักษณะดังนี้

    ////ส่วนของการแสดงผล node แม่(วิทยาเขต) โดยในที่นี้คือ วิทยาเขตตรัง
    <table cellpadding="0" cellspacing="0" style="border-width:0;">
    <tbody>
    <tr>
    <td><a id="TvOrganizationn13"
    href="javascript:TreeView_ToggleNode(TvOrganization_Data,13,document.getElementById('TvOrganizationn13'),' '
    ,document.getElementById('TvOrganizationn13Nodes'))">
    <img src="xxxx" alt="Collapse <span style='color:blue;font-weight:bold'>วิทยาเขตตรัง</span>"
    style="border-width:0;">
    </a></td>
    <td style="white-space:nowrap;"><input type="checkbox" name="TvOrganizationn13CheckBox"
    id="TvOrganizationn13CheckBox"
    title="วิทยาเขตตรัง[5]"><span class="TvOrganization_0" title="วิทยาเขตตรัง[5]" id="TvOrganizationt13">
    <span style="color:blue;font-weight:bold">วิทยาเขตตรัง</span></span></td>
    </tr>
    </tbody>
    </table>

    ////ส่วนของการแสดงผล node ลูก(คณะ/หน่วยงาน) จะมีแท็ก DIV คั่นอยู่ ก่อนจะเจอแท็ก <table></table>ของ node ลูก

    <div id="TvOrganizationn13Nodes" style="display:block;">
    ////ในที่นี้จะมี 2 คณะ/หน่วยงานในวิทยาเขตตรัง คือ คณะพาณิชยศาสตร์และการจัดการ และคณะสถาปัตยกรรมศาสตร์
    ////คณะพาณิชยศาสตร์และการจัดการ
    <table cellpadding="0" cellspacing="0" style="border-width:0;">
    <tbody>
    <tr>
    <td><div style="width:20px;height:1px"></div></td>
    <td><img src="xxx" alt=""></td>
    <td><a href="BasicTreeviewAll.aspx?FacId=46" target="_blank"
    onclick="javascript:TreeView_SelectNode(TvOrganization_Data, this,'TvOrganizationt14');"
    title="คณะพาณิชยศาสตร์และการจัดการ[46]" id="TvOrganizationt14i" tabindex="-1">
    <img src="images/star.png" alt="" style="border-width:0;"></a></td>
    <td style="white-space:nowrap;"><input type="checkbox" name="TvOrganizationn14CheckBox"
    id="TvOrganizationn14CheckBox" title="คณะพาณิชยศาสตร์และการจัดการ[46]">
    <a class="TvOrganization_0" href="BasicTreeviewAll.aspx?FacId=46" target="_blank"
    onclick="javascript:TreeView_SelectNode(TvOrganization_Data, this,'TvOrganizationt14');"
    title="คณะพาณิชยศาสตร์และการจัดการ[46]" id="TvOrganizationt14">คณะพาณิชยศาสตร์และการจัดการ</a></td>
    </tr>
    </tbody>
    </table>
    ////คณะคณะสถาปัตยกรรมศาสตร์
    <table cellpadding="0" cellspacing="0" style="border-width:0;">
    <tbody>
    <tr>
    <td><div style="width:20px;height:1px"></div></td>
    <td><img src="xxxx" alt=""></td>
    <td><a href="BasicTreeviewAll.aspx?FacId=66" target="_blank"
    onclick="javascript:TreeView_SelectNode(TvOrganization_Data, this,'TvOrganizationt15');"
    title="คณะสถาปัตยกรรมศาสตร์[66]" id="TvOrganizationt15i" tabindex="-1">
    <img src="images/star.png" alt="" style="border-width:0;"></a></td>
    <td style="white-space:nowrap;"><input type="checkbox" name="TvOrganizationn15CheckBox"
    id="TvOrganizationn15CheckBox" title="คณะสถาปัตยกรรมศาสตร์[66]">
    <a class="TvOrganization_0" href="BasicTreeviewAll.aspx?FacId=66" target="_blank"
    onclick="javascript:TreeView_SelectNode(TvOrganization_Data, this,'TvOrganizationt15');"
    title="คณะสถาปัตยกรรมศาสตร์[66]" id="TvOrganizationt15">คณะสถาปัตยกรรมศาสตร์</a></td>
    </tr>
    </tbody>
    </table>
    </div>

              จากแถบสีที่เน้นไว้ใน tag HTML ข้างต้น จะเห็นว่า  node แม่(วิทยาเขต)จะถูกสร้างเป็นแท็ก <table> </table> คลุมและถูกคั่นกับ node ลูก ด้วยแท็ก <div> </div> ก่อน node ลูกจะสร้างแท็ก <table> </table> คลุม node ของตัวเอง ทำให้ตอนจัดการกับ node แต่ละแบบใน jQuery จึงแยกส่วน node แม่และลูกด้วยแท็กดังกล่าวนั่นเองค่ะ

  3. ส่วนของ body ในการแสดงผล
    <body>
        <form id="form1" runat="server">
            <asp:TreeView ID="TvOrganization" runat="server" ShowCheckBoxes="All" >
            </asp:TreeView>
        </form>
    </body>

    หมายเหตุ : กรณีที่ต้องการใช้งานเกี่ยวกับ check box อย่าลืมกำหนดคุณสมบัติให้กับ TreeView เพื่อให้สามารถแสดง check box ไว้ด้วยนะคะ ซึ่งก็คือ การกำหนดค่าให้กับ ShowCheckBoxes นั่นเองค่ะ

  4. ตัวอย่างผลลัพธ์
    แบบที่ 1 เลือกที่  node วิทยาเขต จะเลือกที่ node คณะ/หน่วยงานในวิทยาเขตนั้นให้ทั้งหมด

    แบบที่ 2
    หากเลือกออกจากคณะ/หน่วยงานใดหน่วยงานหนึ่ง จะทำการเลือกออกที่  node วิทยาเขตให้อัตโนมัติ

           เพียงเท่านี้ท่านก็จะสามารถดึงข้อมูลจากฐานข้อมูลมาแสดงใน TreeView ของท่านได้แล้ว และนี่ก็อาจจะเป็นเพียงหนึ่งในวิธีการดึงข้อมูลมาแสดงใน TreeView ในเบื้องต้นที่ผู้เขียนศึกษาและนำมาประยุกต์ให้ดูเป็นตัวอย่างเท่านั้น หวังว่าผู้อ่านจะสามารถนำไปเป็นแนวทางในการนำไปประยุกต์ใช้กับงานของท่านได้ นอกจากนี้ท่านยังสามารถผนวกส่วนของการกำหนดคุณสมบัติที่ฝั่ง client กับการกำหนดคุณสมบัติตอนฝั่งเซิร์ฟเวอร์(C#) ร่วมกันได้ เพื่อเพิ่มประสิทธิภาพและลูกเล่นให้กับ TreeView ของท่านมากยิ่งขึ้นค่ะ หากมีส่วนใดผิดพลาดทางผู้เขียนขออภัยไว้ ณ ที่นี้ด้วยนะคะ ขอบคุณค่ะ

แหล่งข้อมูลอ้างอิง :