同事在網頁上用了ASP.NET TreeView控件,但專案規格中需要由Javascript端完成新增節點的動作,很不幸地,這不是ASP.NET TreeView內建支援的功能。

如果時間充裕的話,我會建議改用jQuery TreeView Plugin,較符合大量Client端客製的需求,但因時程迫在眉睫,且只差這個小功能,所以大家不要考究"破解"ASP.NET TreeView前端設計的意義,把它想像成打破水缸救人就好。

寫完這段程式,等同於小小地破解ASP.NET TreeView前端HTML與Script設計。發現原來每一個節點都是一個Table(選擇用Table來配置排列而沒用CSS,應是著眼於相容性,至於要相容誰相信大家心裡有數,讓我們一起吶喊"IE6退散"吧!),其下的子節點則被包在一個DIV中。比較複雜的部分是前方的連接線圖示,圖檔是以Web Resource方式存在,所以URL難以預測,幸好有個TreeView1_ImageArray的字串函數記載了所有圖示的URL,可用Index去找出特定圖示。

不過要考慮節點所在位置不同,有時要用L型,有時要用├,有時要補空白,有時要補直線,麻煩的很,這部分花了不少Code處理。

<%@ Page Language="C#" AutoEventWireup="true" %>
<script type="text/C#" runat="server">
    protected void Page_Load(object sender, EventArgs e)
    {
        if (!IsPostBack)
        {
            TreeNode root = new TreeNode("Root");
            root.ChildNodes.Add(new TreeNode("Catg1"));
            root.ChildNodes.Add(new TreeNode("Catg2"));
            TreeNode node = new TreeNode("Catg3");
            node.ChildNodes.Add(new TreeNode("ItemX"));
            root.ChildNodes.Add(node);
            root.ChildNodes.Add(new TreeNode("Catg4"));
            SetTreeNodeLink(root);
            TreeView1.Nodes.Add(root);
        }
    }
    private void SetTreeNodeLink(TreeNode node)
    {
        node.NavigateUrl = "javascript:selNode('" + node.Text + "');void(0);";
        foreach (TreeNode child in node.ChildNodes)
            SetTreeNodeLink(child);
    }
</script>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title>TreeView Client Script</title>
    <script src="http://ajax.microsoft.com/ajax/jquery/jquery-1.4.2.js?WT.mc_id=DOP-MVP-37580" 
            type="text/javascript"></script>
    <script type="text/javascript">
        $(function () {
            //選取節點時觸發
            window.selNode = function (t) { $("#dvSelNode").text(t); };
            $("#btnAdd").click(function () {
                //註: 此處不考慮父節點名重覆及txtName特殊字元問題
                addNode($("#dvSelNode").text(), $("#txtName").val(),
                    "javascript:selNode('" + $("#txtName").val() + "');void(0);");
            });
            var tvName = "TreeView1";
            var $tv = $("#" + tvName);
            //Icon Url
            var tvIcons = window[tvName + "_ImageArray"];
            //傳回連接線Icon
            function genTreeViewIcon(i) {
                return "<img style='border-width: 0px;' src='" +
                       tvIcons[i] + "' />";
            }
            //查出連接線Icon的索引值,有時要用相對順序算出展開收合狀態的Icon
            function getTreeViewIconIndex(imgUrl) {
                for (var i = 0; i < tvIcons.length; i++)
                    if (tvIcons[i].length > 0 && 
                        imgUrl.indexOf(tvIcons[i]) > -1) return i;
                return -1;
            }
            //加入新節點
            function addNode(parentNodeText, nodeText, nodeLink) {
                //先找到Table
                var $pt = null;
                $tv.find("a").each(function () {
                    if (this.innerHTML == parentNodeText) {
                        $pt = $(this).closest("table");
                        return false;
                    }
                });
                if ($pt) {
                    //找出目前節點的名稱
                    var nodeId = $pt.find("a:last").attr("id");
                    var childBlockId = nodeId.replace("t", "n");
                    //檢查是否已有Child, 若無則加上子節點div
                    if (!$pt.next().is("div")) {
                        //找到前方的圖示
                        var $pfxTd = $pt.find("td").eq(-2);
                        var imgUrl = $pfxTd.find("img").attr("src");
                        //Icon索引+2可換算出可展開的Icon
                        $pfxTd.html(
                            "<a id='" + childBlockId + 
                            "' href=\"javascript:TreeView_ToggleNode(" + tvName + "_Data," +
                            nodeId.substr(nodeId.lastIndexOf("t") + 1, 3) + ","
                            + childBlockId + ",'t'," + childBlockId + "Nodes)\">" +
                            genTreeViewIcon(getTreeViewIconIndex(imgUrl) + 2) +
                            "</a>");
                        $pt.after("<div id='" + childBlockId + "Nodes' style='display: block' />");
                    }
                    var $childBlock = $pt.next();
                    //計算新Node的流水號
                    var maxSn = $tv.find("a").length + 1;
                    var newNodeId = nodeId.substr(0, nodeId.lastIndexOf("t") + 1) + maxSn;
                    //以自己為複製藍本,重點要多加一格後縮
                    var $npt = $pt.clone();
                    //設定節點新值
                    $npt.find("a:last").attr("id", newNodeId).attr("href", nodeLink).text(nodeText);
                    //處理連接線
                    var $cell = $npt.find("td").eq(-2);
                    var imgUrl = $cell.find("img").attr("src");
                    var idx = getTreeViewIconIndex(imgUrl);
                    if (idx >= 11 && idx <= 13) idx = 6; else idx = 3;
                    $cell.html(genTreeViewIcon(idx)) //改連接線
                    .after("<td>" + genTreeViewIcon(13) + "</td>");
                    if ($childBlock.children().length > 0) {
                        //如果已有其他兄弟節點,要改最後一筆兄弟節點的連接線
                        var $lastItem = $childBlock.children("table").last();
                        $cell = $lastItem.find("td").eq(-2);
                        ($cell.children("a").length ? $cell.children("a") : $cell)
                        .html(genTreeViewIcon(
                            getTreeViewIconIndex($cell.find("img").attr("src")) - 3));
                        //若兄弟節點已有子節點也要改其連接線(實在有夠麻煩)
                        if ($lastItem.next().is("div")) {
                            var tdIdx = $lastItem.find("td").length - 2;
                            $lastItem.next().children().each(function () {
                                $(this).find("td:eq(" + tdIdx + ")").html(
                                    genTreeViewIcon(6) //直線
                                );
                            });
                        }
                    }
                    $childBlock.append($npt);
                }
            }
            var h = [];
            for (var i = 0; i < TreeView1_ImageArray.length; i++) {
                h.push("<span>" + i + genTreeViewIcon(i) + "</span>");
            }
            $("#dvDisp").html(h.join("\n"));
        });
    </script>
</head>
<body>
    <form id="form1" runat="server">
    <div id="dvDisp"></div>
    <div>
        <div id="dvSelNode">Not Selected</div>
        <div>
        <input type="text" id="txtName" value="" />
        <input type="button" id="btnAdd" value="Add" />
        </div>
        <asp:TreeView ID="TreeView1" runat="server" Height="250px" ShowLines="True" 
            Width="320px">
        </asp:TreeView>
    </div>
    </form>
</body>
</html>

以上是程式,我當救人兼練功,各位有興趣隨便看看,沒什麼大用。


Comments

# by 91

要改名叫司馬黑暗了 :D 這水缸好麻煩啊...

# by Ark

不爭氣的笑了

Post a comment