欢迎光临
我们一直在努力

可快速绑定到关系表或单表的树-.NET教程,评论及其它

建站超值云服务器,限时71元/月

using system;

using system.collections;

using system.componentmodel;

using system.drawing;

using system.data;

using system.windows.forms;

using system.diagnostics;

namespace upcontrols

{

/// <summary>

/// 可快速绑定到关系表或单表的树,树自动按照主表及其子表的primarykey列值来绑定

/// 只遍历一次rows中的所有行,所以加载速度非常快

/// 结点内容可以只显示值,也可以显示列名称以作说明

/// 关系型的数据源要求具有:子列必需具唯一约束

/// 附加列必需是关系表中的最底层表所拥有的列

/// 适用于parentid,id,text式之外的所有表的树填充

/// </summary>

public class datatreeview : treeview

{

private system.componentmodel.container components = null;

private datatable _maindatatable;

private string[] _appendcolumnnames=null;

private system.windows.forms.contextmenu cntmenu;

private bool _columnnameontext;

private treenode _parentnode;

public datatreeview ()

{

initializecomponent();

menuitem mnu;

mnu=cntmenu.menuitems.add ("显示列名");

mnu.click +=new eventhandler(mnu_click);

mnu=cntmenu.menuitems.add ("-");

mnu=cntmenu.menuitems.add ("展开");

mnu.click +=new eventhandler(mnu_click);

mnu=cntmenu.menuitems.add ("折叠");

mnu.click +=new eventhandler(mnu_click);

mnu=cntmenu.menuitems.add ("-");

mnu=cntmenu.menuitems.add ("全部展开");

mnu.click +=new eventhandler(mnu_click);

mnu=cntmenu.menuitems.add ("全部折叠");

mnu.click +=new eventhandler(mnu_click);

}

/// <summary>

/// 清理所有正在使用的资源。

/// </summary>

protected override void dispose( bool disposing )

{

if( disposing )

{

if(components != null)

{

components.dispose();

}

}

base.dispose( disposing );

}

#region 组件设计器生成的代码

/// <summary>

/// 设计器支持所需的方法 – 不要使用代码编辑器

/// 修改此方法的内容。

/// </summary>

private void initializecomponent()

{

this.cntmenu = new system.windows.forms.contextmenu();

this.cntmenu.popup += new system.eventhandler(this.cntmenu_popup);

this.checkboxes = true;

this.contextmenu = this.cntmenu;

}

#endregion

///////////////////////////////////////////////////////////////////////////////

/// <summary>

/// 主表,主表的第一个primarykey值将添加在树的顶层

/// </summary>

public datatable maintable

{

get{return this._maindatatable ; }

}

/// <summary>

/// 除primarykey列之外的列,可以附加在最后一个primarykey列的结点之下的列

/// </summary>

public string[] appendcolumnnames

{

get{return _appendcolumnnames ; }

}

/// <summary>

/// 结点的文本要否包含列名

/// </summary>

public bool columnnameontext

{

get{return _columnnameontext ; }

}

/// <summary>

/// 填充一个表及其子表到树,结点显示的数据是每一个键列的内容

/// </summary>

/// <param name="datatable">要填充到树的表</param>

/// <param name="parentnode">要填充到哪一个现有的结点之下</param>

/// <param name="appendcolumnnames">附加列(非键列),格式是:表名.列名,或只有列名</param>

/// <param name="columnnameontext">列名要不要显示在结点的文本之中</param>

/// <param name="clearnodes">要不要清除现存的结点再填充</param>

public void fill ( datatable datatable,treenode parentnode,

string[] appendcolumnnames,bool columnnameontext,bool clearnodes)

{

_maindatatable =datatable;

_appendcolumnnames=appendcolumnnames;

_columnnameontext=columnnameontext;

_parentnode=parentnode;

trybinding(clearnodes);

}

/// <summary>

/// 尝试填充树,如果各个必需属性都设置好了

/// </summary>

/// <param name="clearnodes"></param>

public void trybinding(bool clearnodes)

{

if (clearnodes)

{

this.nodes.clear() ;

trybinding(_maindatatable,null,_appendcolumnnames);

}

else

trybinding(_maindatatable,_parentnode,_appendcolumnnames);

}

private void trybinding(datatable datatable,treenode parentnode,

string[] appendcolumnnames)

{

if (datatable==null) return ;

//先加入主表名结点

if (parentnode!=null)

parentnode=parentnode.nodes.add (datatable.tablename );

else

parentnode=this.nodes.add (datatable.tablename );

//返回包含了一个表中所有键列的数组,但是如果表是子表的话,则作为关系的键列不包含在内

//因为父表中存在相同的列值,不需要加载重复内容的结点

datacolumn[] primarykey=addtheseprimarykey(datatable);

treenode[] prinodes=new treenode[primarykey.length ];

string sort=string.empty;

//作排序准备

for (int i=0 ; i < primarykey.length ; i ++ )

sort=sort + "," + primarykey[i].columnname ;

//在下边的数据行遍历中需要确保是按序排列的,快速加载全靠它

sort=sort.trim (,);

//已删除的行当然不要加到树

datarow[] allrows=datatable.select (string.empty,sort,dataviewrowstate.currentrows );

foreach (datarow dr in allrows)

{

//下面的for设置prinodes数组,保证prinodes内有n个node对应于当前行的每一个键列

for (int i=0 ; i < primarykey.length ; i ++ )

{

string colname=primarykey [i].columnname ;

//内容为null,则这一行中这个键列之后的列内容都都不会加到树了

if (dr[colname]==null) break;

treenode nod=new treenode ();

//格式化结点的文本

this.formatnodetext (nod,dr,primarykey [i]);

if (prinodes[i]!=null)

{

//是否已经存在,前面的键列一般是允许重复内容的

if ( prinodes[i].text !=nod.text )

prinodes[i]=nod;

}

else

prinodes[i]=nod;

}

int r =0 ;

treenode pnod=null;

//判断prinodes中的node是否要加到树以及要加到哪里(不能用foreach,顺序不同了)

for (int i=0 ; i < prinodes.length ; i ++ )

{

if (prinodes[i] ==null) break;

treenode nod=prinodes[i];

if (r==0 )

{

if (!parentnode.nodes.contains (nod))

parentnode.nodes.add (nod);

}

else if (!pnod.nodes .contains (nod))

pnod.nodes .add (nod);

pnod=nod;

++r;

}

//在上面的循环中没有被设置,表示每一个键列都是null,虽然不太可能

if (pnod==null) continue;

//附加列必需是关系表中的最底层表

if (datatable.childrelations.count ==0 && appendcolumnnames!=null)

{

foreach (string fullcolname in appendcolumnnames)

{

//appendcolumnnames中的列名可以是:表名.列名,或只有列名

//因为一个表可能有多个关系,而表名起导航作用

string[] fullname=fullcolname.split (.);

string tabname=string.empty,colname=string.empty;

if (fullname.length >1)

{

tabname=fullname[0];

colname=fullname[1];

}

else

{

tabname=datatable.tablename ;

colname=fullname[0];

}

if (tabname==datatable.tablename && datatable.columns .contains (colname))

{

treenode nod=new treenode ();

this.formatnodetext (nod,dr,datatable.columns [colname]);

pnod.nodes.add (nod);

}

}

}

///再填充子表的内容到树,每一个表都只历遍一次rows

foreach (datarelation drl in datatable.childrelations )

trybinding(drl.childtable ,pnod,appendcolumnnames);

}

}

/// <summary>

/// 返回包含了一个表中所有键列的数组,但是如果表是子表的话,则作为关系的键列不包含在内(因为父表中存在相同的列值,不需要加载重复内容的结点)

/// </summary>

/// <param name="dt"></param>

/// <returns></returns>

private datacolumn[] addtheseprimarykey(datatable dt)

{

datacolumn[] keys=null;

arraylist list=new arraylist ();

foreach (datacolumn dc in dt.primarykey)

list.add (dc);

if (dt!=this.maintable )

foreach (datarelation drl in dt.parentrelations )

foreach (datacolumn dc in drl.childcolumns )

list.remove (dc);

if (list.count >0 )

{

keys=new datacolumn [list.count ];

list.copyto (keys,0);

}

return keys;

}

/// <summary>

/// 将结点文本格式化

/// </summary>

/// <param name="node"></param>

/// <param name="datarow"></param>

/// <param name="dc"></param>

private void formatnodetext(treenode node,datarow datarow,datacolumn dc)

{

string nodetext=string.empty,namecol=string.empty,caption=string.empty;

///column_autoid uca=null;

///column_autoid包含了一个id列的编码规则的信息,

///if (dc.extendedproperties.containskey ("ext_autoid"))

///uca=dc.extendedproperties["ext_autoid"] as column_autoid ;

if (datarow.table.columns.contains (dc.columnname ))

{

nodetext=datarow[dc].tostring ().trim ();

///column_autoid.idnamecolumn: 保存一个id列的名称列名,如果有此项,结点文本就可用名称来说明id了,例如用姓名说明人员编号

///if (uca!=null && uca.idnamecolumn !=null)

///{

///namecol=uca.idnamecolumn ;

///if (datarow.table.columns .contains (namecol))

///namecol= datarow[namecol].tostring (); //名称列的值

///}

caption=dc.caption ;

if (dc.datatype ==typeof( boolean) )

{

nodetext=caption;

node.checked = system.convert.toboolean (datarow[dc]);

}

else

{

namecol=namecol==string.empty?namecol:"\t[" + namecol +"]";

if (this.columnnameontext )

nodetext=caption + ":" + nodetext + namecol;

else

nodetext= nodetext + namecol;

}

node.text =nodetext;

}

}

private void cntmenu_popup(object sender, system.eventargs e)

{

}

private void mnu_click(object sender, eventargs e)

{

menuitem mnu=sender as menuitem ;

switch (mnu.index )

{

case 0:

mnu.checked=!mnu.checked;

_columnnameontext=mnu.checked ;

this.trybinding (true);

break;

case 2:

if (this.selectednode !=null)

this.selectednode.expandall ();

break;

case 3:

if (this.selectednode !=null)

this.selectednode.collapse ();

break;

case 5:

this.expandall ();

break;

case 6:

this.collapseall ();

break;

}

}

}

}

赞(0)
版权申明:本站文章部分自网络,如有侵权,请联系:west999com@outlook.com 特别注意:本站所有转载文章言论不代表本站观点! 本站所提供的图片等素材,版权归原作者所有,如需使用,请与原作者联系。未经允许不得转载:IDC资讯中心 » 可快速绑定到关系表或单表的树-.NET教程,评论及其它
分享到: 更多 (0)