在我们做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" /> <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; } }
|