Silverlight中使用递归构造关系图

Silverlight中使用递归构造关系图,第1张

概述这两天遇到一个问题,项目中需要在silverlight中使用连接图的方式来显示任务之间的关系,总体有父子和平行两种,昨天在改同事的代码,一直出问题,索性晚上写了一下实现方法。 需求: 有一个List对象中存了若干个Task,这些Task对象通过ParentID属性进行关联,现在要求将这个List中的任务使用图的方式形成如父子关系和平行关系的图示例如下图: 实现方法思考 刚开始接到这个任务我就想着递

这两天遇到一个问题,项目中需要在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中使用递归构造关系图所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/web/1026755.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-23
下一篇 2022-05-23

发表评论

登录后才能评论

评论列表(0条)

保存