这是三年前在为公司的data collect system写的一个简单树型图生成算法,现在觉得挺有意思的,现在翻出来晒晒一下.
其 实树型图是显示在DataGrid或GridView里的,如下图:
BlanceSheet 1224
├Total Assets 5465433
│└Current Assets 2542
│ ├Cash, Cash Equivalents, and Marketable Securities 245
│ │├Cash and Cash Equivalents 25425
数据表如图所示:
说到显示树型图就可以想js做的树型菜单,不适合放在表格里显示了,还有就是不单要左边显示,右 边要显示数值,更不能直接用什么TreeView控件。我想了很久很久,才开窍想出来,关键就在于如何通知某个结点的子孙节点是应该有“│”,还是应该放 空格!这样树型图才能显示正确。
最终效果图如下:
代码实例:
private
DataView AchiveTreeView(DataView dv)
{
try
{
List < string > nextString = new List < string > ();
GetTreeNode(dv.Table.Rows[ 0 ], 0 , 0 , nextString);
return dv;
}
catch (Exception e)
{
ErrorMsg.Text = e.Message;
ErrorMsg.ToolTip = e.StackTrace;
}
return dv;
}
private void GetTreeNode(DataRow currentRow, int currentIdx, int count,List < string > parentPrefixArr)
{
string mid = currentRow[ " MstarID " ].ToString();
int depth = int .Parse(currentRow[ " Depth " ].ToString());
DataRow[] filterRows = currentRow.Table.Select( " ParentMID=' " + mid + " ' " );
int childCount = filterRows.Length;
int childIndex = 0 ;
List < string > nextString = new List < string > (); // use for prefix of children
if (depth > 0 )
{
string name = currentRow[ " MstarName " ].ToString();
string prefix = "" ;
// achive prefix of children
foreach ( string lastString in parentPrefixArr)
{
prefix += lastString;
nextString.Add(lastString);
}
if (currentIdx < count - 1 )
{
currentRow[ " MstarName " ] = prefix + " ├$ " + name;
nextString.Add( " │ " );
}
else // last of children
{
currentRow[ " MstarName " ] = prefix + " └$ " + name;
nextString.Add( " ** " ); // will be replace when databound event occour
}
}
foreach (DataRow dr in filterRows)
{
GetTreeNode(dr, childIndex, childCount, nextString);
childIndex ++ ;
}
}
protected void MstarView_RowDataBound( object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
string name = e.Row.Cells[ 0 ].Text;
if (name.IndexOf( ' $ ' ) > - 1 )
{
string [] splitarr = name.Split( ' $ ' );
string prefix = " <span style='color:#999999'> " + splitarr[ 0 ] + " </span> " ;
string content = " <b> " + splitarr[ 1 ] + " </b> " ;
name = prefix + content;
}
name = name.Replace( " * " , " " );
e.Row.Cells[ 0 ].Text = name;
}
}
{
try
{
List < string > nextString = new List < string > ();
GetTreeNode(dv.Table.Rows[ 0 ], 0 , 0 , nextString);
return dv;
}
catch (Exception e)
{
ErrorMsg.Text = e.Message;
ErrorMsg.ToolTip = e.StackTrace;
}
return dv;
}
private void GetTreeNode(DataRow currentRow, int currentIdx, int count,List < string > parentPrefixArr)
{
string mid = currentRow[ " MstarID " ].ToString();
int depth = int .Parse(currentRow[ " Depth " ].ToString());
DataRow[] filterRows = currentRow.Table.Select( " ParentMID=' " + mid + " ' " );
int childCount = filterRows.Length;
int childIndex = 0 ;
List < string > nextString = new List < string > (); // use for prefix of children
if (depth > 0 )
{
string name = currentRow[ " MstarName " ].ToString();
string prefix = "" ;
// achive prefix of children
foreach ( string lastString in parentPrefixArr)
{
prefix += lastString;
nextString.Add(lastString);
}
if (currentIdx < count - 1 )
{
currentRow[ " MstarName " ] = prefix + " ├$ " + name;
nextString.Add( " │ " );
}
else // last of children
{
currentRow[ " MstarName " ] = prefix + " └$ " + name;
nextString.Add( " ** " ); // will be replace when databound event occour
}
}
foreach (DataRow dr in filterRows)
{
GetTreeNode(dr, childIndex, childCount, nextString);
childIndex ++ ;
}
}
protected void MstarView_RowDataBound( object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
string name = e.Row.Cells[ 0 ].Text;
if (name.IndexOf( ' $ ' ) > - 1 )
{
string [] splitarr = name.Split( ' $ ' );
string prefix = " <span style='color:#999999'> " + splitarr[ 0 ] + " </span> " ;
string content = " <b> " + splitarr[ 1 ] + " </b> " ;
name = prefix + content;
}
name = name.Replace( " * " , " " );
e.Row.Cells[ 0 ].Text = name;
}
}