using System;
using System.Collections;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Windows.Forms;
using System.Diagnostics;
namespace upControls
{
///
1<summary>
2
3/// 可快速绑定到关系表或单表的树,树自动按照主表及其子表的PrimaryKey列值来绑定
4
5/// 只遍历一次Rows中的所有行,所以加载速度非常快
6
7/// 结点内容可以只显示值,也可以显示列名称以作说明
8
9/// 关系型的数据源要求具有:子列必需具唯一约束
10
11/// 附加列必需是关系表中的最底层表所拥有的列
12
13/// 适用于ParentID,ID,Text式之外的所有表的树填充
14
15/// </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);
}
///
1<summary>
2
3/// 清理所有正在使用的资源。
4
5/// </summary>
protected override void Dispose( bool disposing )
{
if ( disposing )
{
if (components != null )
{
components.Dispose();
}
}
base .Dispose( disposing );
}
#region 组件设计器生成的代码
///
1<summary>
2
3/// 设计器支持所需的方法 - 不要使用代码编辑器
4
5/// 修改此方法的内容。
6
7/// </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
///////////////////////////////////////////////////////////////////////////////
///
1<summary>
2
3/// 主表,主表的第一个primarykey值将添加在树的顶层
4
5/// </summary>
public DataTable MainTable
{
get { return this ._mainDatatable ; }
}
///
1<summary>
2
3/// 除primarykey列之外的列,可以附加在最后一个primarykey列的结点之下的列
4
5/// </summary>
public string [] AppendColumnNames
{
get { return _appendColumnNames ; }
}
///
1<summary>
2
3/// 结点的文本要否包含列名
4
5/// </summary>
public bool ColumnNameOnText
{
get { return _columnNameOnText ; }
}
///
1<summary>
2
3/// 填充一个表及其子表到树,结点显示的数据是每一个键列的内容
4
5/// </summary>
///
1<param name="dataTable"/>
要填充到树的表
///
1<param name="parentNode"/>
要填充到哪一个现有的结点之下
///
1<param name="appendColumnnames"/>
附加列(非键列),格式是:表名.列名,或只有列名
///
1<param name="ColumnnameOnText"/>
列名要不要显示在结点的文本之中
///
1<param name="clearNodes"/>
要不要清除现存的结点再填充
public void Fill ( DataTable dataTable,TreeNode parentNode,
string [] appendColumnnames, bool ColumnnameOnText, bool clearNodes)
{
_mainDatatable =dataTable;
_appendColumnNames=appendColumnnames;
_columnNameOnText=ColumnnameOnText;
_parentNode=parentNode;
TryBinding(clearNodes);
}
///
1<summary>
2
3/// 尝试填充树,如果各个必需属性都设置好了
4
5/// </summary>
///
1<param name="clearNodes"/>
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=