在项目中我们往往需要实现无限级分类,而网上的.NET的例子不是很多,asp的倒是不少,这个算法是我根据网上的asp的例子在结合.net中的TREEVIEW控件来实现多级甚至无限级分类.
对于无限级分类的话,我们首先要考虑的是数据库表要怎么设计,表设计的好对以后的程序实现时很重要的.我的表结构如下:
typeid ,自然为类别id,这是一个自增的字段; pid:存放的是父节点的typeid ; childrenid:存放的是其所有子节点的typeid,中间用','隔开没有子节点默认为空; spath: 路径.存放规则是父节点的spath+'自己的typeid',中间用','隔开。
最后两个字段很重要,有了他们写某些操作时,你会感到很方便,不如需要删除操作何针对某一个类的查找。为了程序算法的方便我设置了一个所谓的根节点(或者叫根类),在程序中它是不可删除的,它的pid设为NULL(这点很重要,下文将说明原因)。
下面我们将以实现功能为例讲解:
1)读取操作,由于。net自带有TREEVIEW控件,能很方便的表现出多级分类的形式所以我选择了它。共有三个方法。
/**/
/// <summary>
///建立树形菜单
/// </summary>
private
void
BuildTree
![](http://www.6635.info/Images/OutliningIndicators/ExpandedBlockStart.gif)
{
System.Data.DataSet ds = cl.getupe;
ds.Relations.Add'NodeRelation', ds.Tables[0].Columns['TypeId'], ds.Tables[0].Columns['pid'];
foreach DataRow dbRow in ds.Tables[0].Rows
![](http://www.6635.info/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
if dbRow.IsNull'pid'
![](http://www.6635.info/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
string strText = '';
string typeid = '';
![](http://www.6635.info/Images/OutliningIndicators/InBlock.gif)
if dbRow['TypeName'] != null
![](http://www.6635.info/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
strText = dbRow['TypeName'].ToString;
typeid = dbRow['TypeId'].ToString;
}
![](http://www.6635.info/Images/OutliningIndicators/InBlock.gif)
TreeNode newNode = CreateNodestrText, typeid;
TreeView1.Nodes.AddnewNode;
PopulateSubTreedbRow, newNode;
}
}
}
![](http://www.6635.info/Images/OutliningIndicators/None.gif)
![](http://www.6635.info/Images/OutliningIndicators/ExpandedBlockStart.gif)
/**/
/// <summary>
/// 采用递归算法创建无限级菜单项
/// </summary>
private
void
PopulateSubTreeDataRow dbRow, TreeNode node
![](http://www.6635.info/Images/OutliningIndicators/ExpandedBlockStart.gif)
{
foreach DataRow childRow in dbRow.GetChildRows'NodeRelation'
![](http://www.6635.info/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
string strText = '';
string typeid = '';
![](http://www.6635.info/Images/OutliningIndicators/InBlock.gif)
if childRow['TypeName'] != null
![](http://www.6635.info/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
strText = childRow['TypeName'].ToString;
typeid = childRow['TypeId'].ToString;
}
![](http://www.6635.info/Images/OutliningIndicators/InBlock.gif)
TreeNode childNode = CreateNodestrText, typeid;
node.ChildNodes.AddchildNode;
PopulateSubTreechildRow, childNode;
}
}
![](http://www.6635.info/Images/OutliningIndicators/None.gif)
![](http://www.6635.info/Images/OutliningIndicators/ExpandedBlockStart.gif)
/**/
/// <summary>
/// 创建菜单子项
/// </summary>
private
TreeNode CreateNode
string
text,
string
typeid
![](http://www.6635.info/Images/OutliningIndicators/ExpandedBlockStart.gif)
{
//javascript:TreeView_ToggleNodeTreeView1_Data,0,TreeView1n0,' ',TreeView1n0Nodes
TreeNode node = new TreeNode;
node.Text = text;
node.Value = typeid;
return node;
}
protected
void
TreeView1_SelectedNodeChanged
object
sender, EventArgs e
![](http://www.6635.info/Images/OutliningIndicators/ExpandedBlockStart.gif)
{
typename.Text = TreeView1.SelectedNode.Text;
HiddenField1.Value = TreeView1.SelectedNode.Value;
}
}
这里采用了dataset的Relations.add 建立了表中数据父子关系(这个方法可以从网上查到详细的说明,在此不再详述。)需要说明的是用此方法根节点的PID必须为空否则会报错。这样在 Page_Load中调用就行了代码如下:
protected
void
Page_Load
object
sender, EventArgs e
![](http://www.6635.info/Images/OutliningIndicators/ExpandedBlockStart.gif)
{
if !IsPostBack
![](http://www.6635.info/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
![](http://www.6635.info/Images/OutliningIndicators/InBlock.gif)
BuildTree;
![](http://www.6635.info/Images/OutliningIndicators/InBlock.gif)
}
}