用户控件-树形结构封装

在我们做Web开发的时候,我们会遇到,选择一项,而这项内容又是一个树形结构,我们一般的做法是,创建一个页面,然后再里面放一个树形控件TreeView,然后设置数据源等等的操作。其实我们仔细分析一下,就可以发现。我们这个树形控件设计到两个事件,一个是加载树形控件的根数据,另外一个当我们单击一个节点的时候,展示该节点下的子节点。对了还需要一个属性。就是返回的数据值,一般我们都需要返回一个名称和值的字符串。然后到根据返回值,进行解析。可以将名称放在文本框或者标签中。值隐藏起来。我想这是asp.net Web程序开发常用的方法。我在想我们是否可以进行封装。然后重用度更高呢。由于我的用户自定义控件开发能力还不行,因此暂时只好使用用户控件进行开发。经过摸索,终于实现了。
    前面我说了,先创建一个用户控件,其前台代码如下:

<%@ Control Language="C#" AutoEventWireup="true" CodeFile="TreeInfo.ascx.cs" Inherits="UUMS_UserControl_base_TreeInfo" %>
<asp:TreeView ID="treeList" runat="server" OnSelectedNodeChanged="treeList_SelectedNodeChanged"
    ImageSet="BulletedList2">
    <SelectedNodeStyle BackColor="#6699FF" />
</asp:TreeView>


    很简单吧,就是放置上一个TreeView控件。同时给这个控件设置一个时间,也是SelectNodeChanged事件。为了做的更通用,所以我们有创建一个事件,也就是上面我所说的事件:public event RootNode LoadRootNodeEvent;public event ChildNodes NodeClick;用户控件的后台代码如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Text;

public abstract partial class UUMS_UserControl_base_TreeInfo : System.Web.UI.UserControl
{
    protected void Page_Load(object sender, EventArgs e)
    {
        if (!Page.IsPostBack)
        {
            this.treeList.Nodes.Clear(); //清空子节点

            TreeNode result = OnRootNodeLoad();
            if (result != null)
            {
                this.treeList.Nodes.Add(result);
            }
            else
            {
                this.treeList.Visible = false; //隐藏树控件。

            }
        }
    }

    /// <summary>

    /// 定义根据父节点编号,获取子节点的集合的指代

    /// </summary>

    /// <param name="fatherNodeValue">父节点值</param>

    /// <returns>IList TreeNode类型值</returns>

    public delegate IList<TreeNode> ChildNodes(string fatherNodeValue);

    /// <summary>

    /// 定义根节点指代

    /// </summary>

    /// <returns>TreeNode值</returns>

    public delegate TreeNode RootNode();

    /// <summary>

    /// 节点点击事件

    /// </summary>

    public event ChildNodes NodeClick;

    /// <summary>

    /// 定义加载根节点事件

    /// </summary>

    public event RootNode LoadRootNodeEvent;

    /// <summary>

    /// 选择节点后,返回的字符串值(名称|ID)

    /// </summary>

    public virtual string ReturnString
    {
        get
        {
            StringBuilder result = new StringBuilder();
            TreeNode selNode = this.treeList.SelectedNode;
            if (selNode != null)
            {
                result.Append(selNode.Text);
                result.Append("|");
                result.Append(selNode.Value);
            }

            return result.ToString();
        }
    }


    protected void treeList_SelectedNodeChanged(object sender, EventArgs e)
    {
        TreeNode selenode = this.treeList.SelectedNode;
        IList<TreeNode> result = OnNodeClick(selenode.Value); //引发单击事件

        if (result != null)
        {
            selenode.ChildNodes.Clear();//清空所有的子节点

            foreach (TreeNode item in result)
            {
                selenode.ChildNodes.Add(item);
            }
        }
    }

    protected IList<TreeNode> OnNodeClick(string fatherNodeValue)
    {
        IList<TreeNode> result = null;
        if (NodeClick != null)
        {
            result = NodeClick(fatherNodeValue);
        }
        return result;
    }

    protected TreeNode OnRootNodeLoad()
    {
        TreeNode result = null;
        if (LoadRootNodeEvent != null)
        {
            result = LoadRootNodeEvent();
        }

        return result;
    }
}


    用户控件编写好后,然后我们创建一个asp.net页面将自己编写的用户控件添加到页面上,前台代码如下:

<%@ Page Language="C#" AutoEventWireup="true" CodeFile="SelectCategory.aspx.cs" Inherits="UUMS_Category_SelectCategory" %>

<%@ Register Src="../UserControl/base/TreeInfo.ascx" TagName="TreeInfo" TagPrefix="uc1" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title>选择类别</title>
    <link href="http://www.cnblogs.com/css/default/StyleSheet.css" rel="stylesheet" type="text/css" />
    <base target="_self" />
    <!--设置在本窗体内进行刷新-->
</head>
<body>
    <form id="form1" runat="server">
    <uc1:TreeInfo ID="TreeInfo1" runat="server" />
    <br />
    <asp:Button ID="btnEnter" runat="server" Text="确定" OnClick="btnEnter_Click" />&nbsp;
    <asp:Button ID="btnCancel" runat="server" Text="取消" OnClick="btnCancel_Click" Style="height: 26px" />
    </form>
</body>
</html>


因为我们是弹出的页面,所以要设置<base target="_self" />这样弹出的页面,进行数据回发的时候,在自己的页面中进行,否则当单击一个节点的时候,会弹出一个页面。从前台代码中我们可以看到一个我们放了两个Button,当确定的时候,将选择的节点和值传回,取消时,返回空字符串。看下面的后台代码你就明白了,代码如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using UUMS.BLL;
using UUMS.Model;

public partial class UUMS_Category_SelectCategory : WebPageBase
{
    CategoryManage manage = new CategoryManage();
    public override string PageID
    {
        get { return "SelectCategory"; }
    }
    protected void Page_Load(object sender, EventArgs e)
    {
        this.TreeInfo1.LoadRootNodeEvent += new UUMS_UserControl_base_TreeInfo.RootNode(TreeInfo1_LoadRootNodeEvent);
        this.TreeInfo1.NodeClick += new UUMS_UserControl_base_TreeInfo.ChildNodes(TreeInfo1_NodeClick);
    }

    protected void btnEnter_Click(object sender, EventArgs e)
    {
        Response.Write("<script>window.returnValue=\'" + this.TreeInfo1.ReturnString + "\';window.opener=null;window.open( '', '_self');window.close();</script>"); //关闭页面,并返回返回值

    }
    protected void btnCancel_Click(object sender, EventArgs e)
    {
        Response.Write("<script>window.returnValue='';window.opener=null;window.open( '', '_self');window.close();</script>"); //关闭页面,返回空值

    }

    TreeNode TreeInfo1_LoadRootNodeEvent()
    {
        int cat_id = 1;
        if (Request["cat_id"] != null)
        {
            cat_id = RequestID("cat_id");
            
        }
        return GetTreeNode(cat_id.ToString());
    }

    IList<TreeNode> TreeInfo1_NodeClick(string fatherNodeValue)
    {
        IList<TreeNode> result = null;
        int nodeValue = base.ConvertInt32Value(fatherNodeValue);
        IList<CategoryInfo> allCategory = manage.GetCategoryList(nodeValue);
        if (allCategory != null)
        {
            result = new List<TreeNode>();
            foreach (CategoryInfo item in allCategory)
            {
                result.Add(new TreeNode(item.CategoryName, item.CategoryID.ToString()));
            }
        }

        return result;
    }

    public TreeNode GetTreeNode(string nodeValue)
    {
        TreeNode result = null;
        int node = 1;
        nodeValue = string.IsNullOrEmpty(nodeValue) ? "1" : nodeValue;
        node = base.ConvertInt32Value(nodeValue);

        CategoryInfo catInfo = manage.GetCategory(node);
        if (catInfo != null)
        {
            result = new TreeNode();
            result.Text = catInfo.CategoryName;
            result.Value = catInfo.CategoryID.ToString();
        }
        return result;
    }
}


    其实主要的设计思想是,用户控件只负责数据的展示,不涉及业务逻辑。业务逻辑有页面提供。不然的话,你设计的用户控件封装了太多的业务逻辑而影响用户控件重用。

= = = = = = = = = = = = = = = = = = = = = = = = = = =

    为了更方便的引用这个树形控件,我们需要做的是,放置一个文本框,显示节点的名称,然后点击后面的image,然后弹出上面说的选择树形结构的aspx页面.因为我又设计了一个展示选择后展示的页面。也是用用户控件进行设计。代码代码如下:

<%@ Control Language="C#" AutoEventWireup="true" CodeFile="FatherInfo.ascx.cs" Inherits="UUMS_UserControl_base_FatherInfo" %>
<script language="javascript" type="text/javascript">
    //弹出窗体,并将返回值为两个文本框进行设置(特殊用途)
    //引用于:~/UUMS/UserControl/base/FatherInfo.ascx.cs文件
    //xiaopeng 2010.10.30 created
    function My_ShowModalDialog(url, para, elementName, elementValue) {
        var result = window.showModalDialog(url, null, para); //返回的字符串为'名称|',因此按以下规则进行分割
        if (result != "") {
            document.getElementById(elementName).value = result.split("|")[0]; //名称
            document.getElementById(elementValue).value = result.split("|")[1]; //
        }
    }
</script>
<style type="text/css">
    .hand {cursor: hand;}
    
    /* 设置此样式是因为控件asp:TextBox,如果设置Visible="false"时,*/
    /* 则不能呈现控件,这样我们写的js代码就找不到这个控件,因此失效*/
    /* 所以,设置此样式,让TextBox控件隐藏起来,这样方便我们去操作。*/
    /* xiaopeng 2010.10.30 created */
    .hidden {display:none;}
</style>
<td class="clsCellBold" style="width: 20%;">
    <asp:Label ID="lblName" runat="server">父节点名称</asp:Label>
    <asp:Label ID="lblCode" runat="server" Visible="false" />
</td>
<td class="clsCellEdit" style="width: 30%;">
    <asp:TextBox ID="txtName" runat="server" ReadOnly="true" CssClass="clsCellText" Width="70%" />
    <asp:Image ImageUrl ="http://www.cnblogs.com/../css/default/images/select.gif"
    runat="server" id="img_sel" ImageAlign="Middle" CssClass="hand" />
    <asp:TextBox ID="txtCode" runat ="server" CssClass="hidden" Width="98%" />
</td>


    因为要动态的获取两个文本框在客户端展示时的ID和涉及Image的单击事件,因此我在后台代码,获取两个TextBox控件的ClientID,另外后台还提供了一些属性为设置一个标签等提供了方便。代码如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;

public partial class UUMS_UserControl_base_FatherInfo:UserControlBase
{
    private PopPageValue _popValue = null;
    protected void Page_Load(object sender, EventArgs e)
    {
        if (!Page.IsPostBack)
        {
            if (PopPageInfo != null)
            {
                this.img_sel.Attributes.Add("onclick", "My_ShowModalDialog(\'" + PopPageInfo.URL + "\',\'" + PopPageInfo.ParaValue
                    + "\',\'" + this.txtName.ClientID.ToString()+ "\',\'" + this.txtCode.ClientID.ToString() + "\')");
            }
        }
    }


    /// <summary>

    /// 弹出页面信息类

    /// </summary>

    public PopPageValue PopPageInfo
    {
        get { return this._popValue; }
        set { this._popValue = value; }
    }


    public string FatherValue
    {
        get { return this.txtCode.Text; }
        set { this.txtCode.Text = value; }
    }

    public string FatherName
    {
        get { return this.txtName.Text; }
        set { this.txtName.Text = value; }
    }

    public string LabelFahterValue
    {
        get { return this.lblCode.Text; }
        set { this.lblCode.Text = value; }
    }

    public string LabelFatherName
    {
        get { return this.lblName.Text; }
        set { this.lblName.Text = value; }
    }
}


然后引用这个用户控件的页面只需要设置PopPageInfo即可。代码片段如下:

protected void Page_Load(object sender, EventArgs e)
    {
        if (!Page.IsPostBack)
        {
            this.NameCodeInfo1.LabelCode = "类别编号";
            this.NameCodeInfo1.LabelName = "类别名称";
            this.FatherInfo11.PopPageInfo = SelectFatherPage;
        }
    }



    //选择父节点弹出页面的相关参数设置

    public PopPageValue SelectFatherPage
    {
        get
        {
            PopPageValue result = new PopPageValue();
            result.URL = "SelectCategory.aspx";
            result.ParaValue = "dialogWidth=200px;dialogHeight=400px";
            return result;
        }
    }

posted @ 2010-11-04 21:23  程晓鹏  阅读(1152)  评论(1编辑  收藏  举报