这两天遇到一个问题,项目中需要在silverlight中使用连接图的方式来显示任务之间的关系,总体有父子和平行两种,昨天在改同事的代码,一直出问题,索性晚上写了一下实现方法。
需求:有一个List对象中存了若干个Task,这些Task对象通过ParentID属性进行关联,现在要求将这个List中的任务使用图的方式形成如父子关系和平行关系的图示例如下图:
实现方法思考刚开始接到这个任务我就想着递归应该可以搞定了,但是仔细考虑才发现每个任务的子任务需要在一定区域内才行,需要计算子级和子级之间的距离,如果使用递归,例如上图的元素“12”的位置就没有办法很好确定了。
我决定将途中的节点抽象为一个类,这个类至少应该含有上边界top,左边届left及节点的名称等属性,然后从这个List对象中构造出每个节点的属性。
实现步骤1,首先我们为图模拟一个数据源,注意其中的任务是通过ParentID关联的
代码 private static List < Task > ListTask;
public MainPage()
{
InitializeComponent();
ListTask = new List < Task > ();
ListTask.Add( new Task() { ID = 1 , ParentID = 0 , name = " 1 " });
ListTask.Add( new Task() { ID = 2 , ParentID = 1 , name = " 11 " });
ListTask.Add( new Task() { ID = 3 , name = " 12 " });
ListTask.Add( new Task() { ID = 4 , ParentID = 2 , name = " 21 " });
ListTask.Add( new Task() { ID = 5 , name = " 22 " });
ListTask.Add( new Task() { ID = 6 , ParentID = 3 , name = " 31 " });
ListTask.Add( new Task() { ID = 7 , name = " 32 " });
ListTask.Add( new Task() { ID = 8 , name = " 33 " });
ListTask.Add( new Task() { ID = 9 , ParentID = 4 , name = " 42 " });
ListTask.Add( new Task() { ID = 10 , ParentID = 4 , name = " 42 " });
ListTask.Add( new Task() { ID = 11 , ParentID = 3 , name = " 34 " });
ListTask.Add( new Task() { ID = 12 , ParentID = 5 , name = " 51 " });
ListTask.Add( new Task() { ID = 13 , ParentID = 8 , name = " 81 " });
this .Loaded += new RoutedEventHandler(MainPage_Loaded);
}
2,然后我们为要生成的图中节点构造一个类
代码 class TaskPro
{
public Task task { set ; get ; }
public double top { set ; get ; }
public double left { set ; get ; }
public int index { set ; get ; } // 这是为了找到节点在某层的位置来计算left
}
3,使用递归将List中的数据做初步整理,存入一个List<TaskPro>中,此时节点对象将具备top属性,上边距搞定。
代码 voID AddMethod(Task task)
{
if (task.ParentID == 0 )
{
listofTaskPro.Add( new TaskPro() { task = task, top = 0 , index = 0 , left = 0 });
}
else
{
var t = ListTask.Where(m => m.ID == task.ParentID).FirstOrDefault();
var tpro = listofTaskPro.Where(m => m.task.ID == t.ID).FirstOrDefault();
listofTaskPro.Add( new TaskPro() { task = task, index = 0 , top = tpro.top + 50 , left = 0 });
}
foreach (Task t in ListTask.Where(m => m.ParentID == task.ID).ToList())
{
AddMethod(t);
}
}
4,我们需要算出节点对象的左边距,在第3步中我没能找到方法,于是想到利用每一级的元素个数来计算每个节点的位置,然后使用每一级的平均节点距离*节点的索引便可得到left
代码 // 构造各层及数量
foreach (TaskPro t in listofTaskPro)
{
bool IsExist = false ;
foreach (TaskCount tc in ListtopAndTasks)
{
IsExist = tc.top == t.top ? true : false ;
}
if ( ! IsExist)
{
ListtopAndTasks.Add( new TaskCount() { top = t.top, Tasks = new List < Task > () });
}
var topAndTasks = ListtopAndTasks.Where(m => m.top == t.top).FirstOrDefault();
topAndTasks.Tasks.Add(t.task);
}
// 构造index
foreach (TaskPro t in listofTaskPro)
{
for ( int i = 0 ; i < ListtopAndTasks.Count; i ++ )
{
for ( int j = 0 ; j < ListtopAndTasks[i].Tasks.Count; j ++ )
{
if (ListtopAndTasks[i].Tasks[j].ID == t.task.ID)
{
t.index = j + 1 ;
}
}
}
}
// 构造left
for ( int i = 0 ; i < listofTaskPro.Count; i ++ )
{
if (listofTaskPro[i].task.ParentID == 0 )
{
listofTaskPro[i].left = this .canvas1.WIDth / 2 ;
}
else
{
var childCount = listofTaskPro.Where(m => m.task.ParentID == listofTaskPro[i].task.ParentID).Count();
var parentleft = listofTaskPro.Where(m => m.task.ID == listofTaskPro[i].task.ParentID).FirstOrDefault().left;
var perLength = parentleft * 1.5 / (childCount + 1 );
listofTaskPro[i].left = listofTaskPro[i].index * perLength;
}
}
5,至此,节点对象已经具备了left,top属性,我们只需要找到每个节点的父节点即可将两个几点的坐标确定,进而进行划线的 *** 作了。
代码 foreach (TaskPro t in listofTaskPro)
{
AddBtn(t.task.name, t.left, t.top);
if (t.task.ParentID != 0 )
{
TaskPro tp = listofTaskPro.Where(m => m.task.ID == t.task.ParentID).FirstOrDefault();
Addline(tp.left + buttonWIDth / 2 , tp.top + buttonHeight, t.left + buttonWIDth / 2 , t.top);
}
}
6,添加按钮及划线的方法
代码 #region 添加按钮及线条
double buttonHeight = 20 ;
double buttonWIDth = 50 ;
voID AddBtn( string content, double left, double top)
{
button btn = new button();
btn.Content = content;
btn.WIDth = buttonWIDth;
btn.Height = buttonHeight;
this .canvas1.Children.Add(btn);
Canvas.Setleft(btn, left);
Canvas.Settop(btn, top);
}
// 画线方法,只需要有起始亮点的坐标即可
voID Addline( double startleft, double starttop, double endleft, double endtop)
{
Path p = new Path();
lineGeometry geometry = new lineGeometry();
SolIDcolorBrush brush = new SolIDcolorBrush();
brush.color = colors.Black;
geometry.StartPoint = new Point(startleft, starttop);
geometry.EndPoint = new Point(endleft, endtop);
p.Data = geometry;
p.stroke = brush;
p.strokeThickness = 1 ;
canvas1.Children.Add(p);
}
#endregion
运行一下,如上图。
之前没有使用递归的方法是只有这样的:
代码 using System;using System.Collections.Generic;
using System.linq;
using System.Net;
using System.windows;
using System.windows.Controls;
using System.windows.documents;
using System.windows.input;
using System.windows.Media;
using System.windows.Media.Animation;
using System.windows.Shapes;
namespace SilverlightApplication2
{
public class Task
{
public int ID { set ; get ; }
public int ParentID { set ; get ; }
public string name { set ; get ; }
}
public partial class MainPage : UserControl
{
private static List < Task > ListTask;
public MainPage()
{
InitializeComponent();
ListTask = new List < Task > ();
ListTask.Add( new Task() { ID = 1 , name = " 81 " });
this .Loaded += new RoutedEventHandler(MainPage_Loaded);
}
voID MainPage_Loaded( object sender, RoutedEventArgs e)
{
AddAll();
}
class TaskPro
{
public Task task { set ; get ; }
public double top { set ; get ; }
public double left { set ; get ; }
public int index { set ; get ; }
}
class TaskCount
{
public double top { set ; get ; }
public List < Task > Tasks { set ; get ; }
}
static List < TaskPro > ListTaskPro = new List < TaskPro > ();
static List < TaskCount > ListtopAndTasks = new List < TaskCount > ();
voID AddAll()
{
foreach (Task t in ListTask)
{
if (t.ParentID == 0 )
{
ListTaskPro.Add( new TaskPro() { task = t, index = 1 , left = this .canvas1.WIDth / 2 , top = 0 });
}
else
{
for ( int i = 0 ;i < ListTaskPro.Count;i ++ )
{
if (t.ParentID == ListTaskPro[i].task.ID)
{
ListTaskPro.Add( new TaskPro() { task = t, top = ListTaskPro[i].top + 80 , left = 0 });
}
}
}
}
#region 汇总层及层内的元素个数
foreach (TaskPro t in ListTaskPro)
{
bool IsExist = false ;
foreach (TaskCount tc in ListtopAndTasks)
{
if (tc.top == t.top)
{
IsExist = true ;
}
}
if ( ! IsExist)
{
ListtopAndTasks.Add( new TaskCount() { top = t.top, Tasks = new List < Task > () });
}
var topAndTasks = ListtopAndTasks.Where(m => m.top == t.top).FirstOrDefault();
topAndTasks.Tasks.Add(t.task);
}
#endregion
foreach (TaskPro t in ListTaskPro)
{
for ( int i = 0 ; i < ListtopAndTasks.Count;i ++ )
{
for ( int j = 0 ; j < ListtopAndTasks[i].Tasks.Count;j ++ )
{
if (ListtopAndTasks[i].Tasks[j].ID == t.task.ID)
{
t.index = j + 1 ;
}
}
}
}
for ( int i = 0 ; i < ListTaskPro.Count; i ++ )
{
if (ListTaskPro[i].task.ParentID == 0 )
{
ListTaskPro[i].left = this .canvas1.WIDth / 2 ;
}
else
{
var childCount = ListTaskPro.Where(m => m.task.ParentID == ListTaskPro[i].task.ParentID).Count();
var parentleft = ListTaskPro.Where(m => m.task.ID == ListTaskPro[i].task.ParentID).FirstOrDefault().left;
var perLength = parentleft * 1.5 / (childCount + 1 );
ListTaskPro[i].left = ListTaskPro[i].index * perLength;
}
}
foreach (TaskPro t in ListTaskPro)
{
AddBtn(t.task.name, t.top);
if (t.task.ParentID != 0 )
{
TaskPro tp = ListTaskPro.Where(m => m.task.ID == t.task.ParentID).FirstOrDefault();
Addline(tp.left + buttonWIDth / 2 , tp.top + buttonHeight, t.left + buttonWIDth / 2 , t.top);
}
}
}
double buttonHeight = 20 ;
double buttonWIDth = 50 ;
voID AddBtn( string content, double left, double top)
{
button btn = new button();
btn.Content = content;
btn.WIDth = buttonWIDth;
btn.Height = buttonHeight;
this .canvas1.Children.Add(btn);
Canvas.Setleft(btn, top);
}
voID Addline( double startleft, double starttop, double endleft, double endtop)
{
Path p = new Path();
lineGeometry geometry = new lineGeometry();
SolIDcolorBrush brush = new SolIDcolorBrush();
brush.color = colors.Black;
geometry.StartPoint = new Point(startleft, endtop);
p.Data = geometry;
p.stroke = brush;
p.strokeThickness = 1 ;
canvas1.Children.Add(p);
}
}
}
如果您有更好的方法,希望不吝赐教,我正在不断修正代码,希望能更简洁。
总结以上是内存溢出为你收集整理的Silverlight中使用递归构造关系图全部内容,希望文章能够帮你解决Silverlight中使用递归构造关系图所遇到的程序开发问题。
如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)