天天看點

使用Asp.net的TreeView來建構使用者選擇輸入

選擇優于輸入,這是一般人的共識,面對繁多的資料,提供良好的選擇界面,一方面增強使用者的界面體驗,一方面也提高了資料的準确性,更節省了使用者的寶貴時間。一般的單項資料選擇可以使用DropdownList控件來實作,但對于有多個選擇性輸入,而且輸入有層次關系的内容,最好選擇TreeView控件來實作。

本文介紹如何使用使用TreeView控件來有效擷取使用者的輸入,其中涉及到TreeView控件的級聯選擇、去掉節點HTML連結變為展開目錄、擷取選擇内容、如何構造資料庫的資訊變為樹形内容以及彈出視窗使用等知識點,本文輸入應用級别的例子,希望能做個記号,對己對人,皆為利好!^_^

本文的經營範圍是一個可以輸入分類及詳細子内容的,由于内容繁多,而且具有一定的層次關系,是以,不适合采用DropdownList和CheckboxList控件,是以采用了帶CheckBox屬性的TreeView控件來輔助使用者的輸入。

輸入界面大緻如下所示,使用者通過選擇按鈕,觸發彈出對話框,在對話框中放置了TreeView控件。

在彈出的對話框中,放置的TreeView控件,一個帶有CheckBox,可以友善使用者選擇,并且具有級聯(通過Javascript實作,減少Post回發),另外由于内容比較多,我設定了展開的級别層次。

使用者通過選擇或者反選大類,可以選擇或反選其清單下面的所有項目,也可以單獨選擇子項目。

由于通過Javascript不太好擷取并組裝傳回的内容,本文通過了在背景周遊樹的方式對傳回值進行處理,然後在父窗體的Javascript中對傳回值進行了綁定,使其在界面控件中得以顯示指定格式的内容。

以下為HTML的代碼,其中OnTreeNodeChecked為級聯Javascript函數,SubmitValue為對傳回值進行綁定的操作。

    <div class="search">

        <span>

            <asp:ImageButton ID="btnSelect" runat="server" 

            ImageUrl="~/Themes/Default/btn_select.gif" onclick="btnSelect_Click"

                />

            <asp:ImageButton ID="btnClose" runat="server" OnClientClick="javascript:window.close();return false;"

                ImageUrl="~/Themes/Default/btn_close.gif" />

        </span>

        <table cellspacing="0" cellpadding="0" border="0" width="100%">

            <tr>

                <td class="ico">

                     

                </td>

                <td class="form">

                    <asp:TreeView ID="TreeView1" runat="server" onclick="OnTreeNodeChecked();" ShowCheckBoxes="All"

                        ShowLines="True" ExpandDepth="1" Font-Bold="False" ForeColor="#0000CC">

                    </asp:TreeView>

            </tr>

        </table>

    </div>

    <script language='javascript' type='text/javascript'>

        function OnTreeNodeChecked() {

            var ele = event.srcElement;

            if (ele.type == 'checkbox') {

                var childrenDivID = ele.id.replace('CheckBox', 'Nodes');

                var div = document.getElementById(childrenDivID);

                if (div == null) return;

                var checkBoxs = div.getElementsByTagName('INPUT');

                for (var i = 0; i < checkBoxs.length; i++) {

                    if (checkBoxs[i].type == 'checkbox')

                        checkBoxs[i].checked = ele.checked;

                }

            }

        }

        function SubmitValue() {

            var val = "";

            var returnVal = new Array();

            var inputs = document.all.tags("INPUT");

            var n = 0;

            for (var i = 0; i < inputs.length; i++) // 周遊頁面上所有的 input 

            {

                if (inputs[i].type == "checkbox") {

                    if (inputs[i].checked) {

                        var strValue = inputs[i].value;

                        val += strValue + ',';

                        //returnVal[n] = val;

                        n = n + 1;

                    }

                } //if(inputs[i].type="checkbox")

            } //for

            window.returnValue = val;

            window.close();

    </script>

 下面代碼是頁面的背景代碼,其中展示了如何對樹進行資料綁定,使其能夠顯示有層次格式的内容,其中AddTreeNode是一個遞歸函數。btnSelect_Click事件處理函數,專門對傳回的資料進行組裝,以一定的格式顯示到用戶端的控件輸入上。

  代碼

        protected void Page_Load(object sender, EventArgs e)

        {

            if (!this.IsPostBack)

                BindData();

        private void BindData()

            ArrayList scopeTree = BLLFactory<BusinessScope>.Instance.GetTree();

            foreach (BusinessScopeNodeInfo nodeInfo in scopeTree)

                TreeNode node = new TreeNode(nodeInfo.Name);

                node.SelectAction = TreeNodeSelectAction.Expand;

                this.TreeView1.Nodes.Add(node);

                AddTreeNode(node, nodeInfo);

        private void AddTreeNode(TreeNode parentNode, BusinessScopeNodeInfo nodeInfo)

            TreeNode treeNode = null;

            foreach (BusinessScopeNodeInfo subNodeInfo in nodeInfo.Children)

                treeNode = new TreeNode(subNodeInfo.Name);

                treeNode.SelectAction = TreeNodeSelectAction.Expand;

                parentNode.ChildNodes.Add(treeNode);

                AddTreeNode(treeNode, subNodeInfo);

        protected void btnSelect_Click(object sender, ImageClickEventArgs e)

            string result = "";

            foreach (TreeNode parent in this.TreeView1.Nodes)

                foreach (TreeNode node in parent.ChildNodes)

                {

                    StringBuilder sb = new StringBuilder();

                    foreach (TreeNode subNode in node.ChildNodes)

                    {

                        if (subNode.Checked)

                        {

                            sb.AppendFormat("{0},", subNode.Text);

                        }

                    if (sb.Length > 0)

                        sb.Insert(0, string.Format("{0}(", node.Text));

                        sb.Append(")");

                        result += sb.ToString().Replace(",)", ")") + ";";

                    else if (node.Checked)

                        result += node.Text;

                    }                    

            Helper.CloseWin(this, result.Trim(';'));

 其中數的資料組裝也是需要注意的一個地方,為了提高效率,避免頻繁查找資料庫,我們先把符合條件的資料放到DataTable,然後通過對象的Select在記憶體中查找,這樣可以很好的提高遞歸函數的查找效率。

        /// <summary>

        /// 擷取資料樹

        /// </summary>

        /// <returns></returns>

        public ArrayList GetTree()

            ArrayList arrReturn = new ArrayList();

            string sql = string.Format("Select * From {0} Order By PID, Seq ", tableName);

            Database db = DatabaseFactory.CreateDatabase();

            DbCommand cmdWrapper = db.GetSqlStringCommand(sql);

            DataSet ds = db.ExecuteDataSet(cmdWrapper);

            if (ds.Tables.Count > 0)

                DataTable dt = ds.Tables[0];

                DataRow[] dataRows = dt.Select(string.Format(" PID = {0}", -1));

                for (int i = 0; i < dataRows.Length; i++)

                    int id = Convert.ToInt32(dataRows[i]["ID"]);

                    BusinessScopeNodeInfo menuNodeInfo = GetNode(id, dt);

                    arrReturn.Add(menuNodeInfo);

            return arrReturn;

        private BusinessScopeNodeInfo GetNode(int id, DataTable dt)

            BusinessScopeInfo menuInfo = this.FindByID(id);

            BusinessScopeNodeInfo menuNodeInfo = new BusinessScopeNodeInfo(menuInfo);

            DataRow[] dChildRows = dt.Select(string.Format(" PID={0}", id));

            for (int i = 0; i < dChildRows.Length; i++)

                int childId = Convert.ToInt32(dChildRows[i]["ID"]);

                BusinessScopeNodeInfo childNodeInfo = GetNode(childId, dt);

                menuNodeInfo.Children.Add(childNodeInfo);

            return menuNodeInfo;

 其中所用到的資料實體如下面兩個類所示,其中BusinessScopeNodeInfo 是對象 BusinessScopeInfo的進一步封裝,友善提供樹的基本資訊,也就是BusinessScopeNodeInfo 是一個包含了子類資料的對象,BusinessScopeInfo僅僅是資料庫對象的映射實體。

代碼

    /// <summary>

    /// BusinessScopeNodeInfo 的摘要說明。

    /// </summary>

    public class BusinessScopeNodeInfo : BusinessScopeInfo

    {

        private ArrayList m_Children = new ArrayList();

        /// 子菜單實體類對象集合

        public ArrayList Children

            get { return m_Children; }

            set { m_Children = value; }

        public BusinessScopeNodeInfo()

            this.m_Children = new ArrayList();

        public BusinessScopeNodeInfo(BusinessScopeInfo scopeInfo)

            base.Id = scopeInfo.Id;

            base.Name = scopeInfo.Name;

            base.Seq = scopeInfo.Seq;

    }

    [Serializable]

    public class BusinessScopeInfo : BaseEntity

    {    

        #region Field Members

        private decimal m_Id = 0;         

        private decimal m_Pid = -1;         

        private string m_Name = "";         

        private string m_Seq = "";         

        #endregion

        #region Property Members

        public virtual decimal Id

            get

                return this.m_Id;

            set

                this.m_Id = value;

        public virtual decimal Pid

                return this.m_Pid;

                this.m_Pid = value;

        public virtual string Name

                return this.m_Name;

                this.m_Name = value;

        public virtual string Seq

                return this.m_Seq;

                this.m_Seq = value;

其中的資料格式大緻如下(本文的例子是在Oracle環境中工作的),其實SqlServer或者其他資料庫也是一樣。