现在很多的javascript控件,非常的不错,其中step就是一个,如下图所示:
那么如何用C#来实现一个step控件呢?
先定义一个StepEntity类来存储步骤条节点的信息:
1 public class StepEntity 2 { 3 public string Id { get; set; } 4 public string StepName { get; set; } 5 public int StepOrder { get; set; } 6 public eumStepState StepState { get; set; } 7 public string StepDesc { get; set; } 8 public object StepTag { get; set; } 9 //public Image StepCompletedImage { get; set; } 10 //public Image StepDoingImage { get; set; } 11 public StepEntity(string id,string stepname,int steporder,string stepdesc, eumStepState stepstate,object tag) 12 { 13 this.Id = id; 14 this.StepName = stepname; 15 this.StepOrder = steporder; 16 this.StepDesc = stepdesc; 17 this.StepTag = tag; 18 this.StepState = stepstate; 19 } 20 }
定义一个名为StepViewer 的用户控件。
1 public partial class StepViewer : UserControl 2 { 3 public StepViewer() 4 { 5 InitializeComponent(); 6 this.Height = 68; 7 } 8 }
在StepViewer 的用户控件中定义一个ListDataSource的属性,如下:
1 private List<StepEntity> _dataSourceList = null; 2 [Browsable(true), Category("StepViewer")] 3 public List<StepEntity> ListDataSource 4 { 5 get 6 { 7 return _dataSourceList; 8 } 9 set 10 { 11 if (_dataSourceList != value) 12 { 13 _dataSourceList = value; 14 Invalidate(); 15 } 16 } 17 }
在此控件的paint方法中,进行步骤条的绘制:
1 private void StepViewer_Paint(object sender, PaintEventArgs e) 2 { 3 if(this.ListDataSource!=null) 4 { 5 int CenterY = this.Height / 2; 6 int index = 1; 7 int count = ListDataSource.Count; 8 int lineWidth = 120; 9 int StepNodeWH = 28; 10 //this.Width = 32 * count + lineWidth * (count - 1) + 6+300; 11 //defalut pen & brush 12 e.Graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality; 13 Brush brush = new SolidBrush(_Gray); 14 Pen p = new Pen(brush, 1f); 15 Brush brushNode = new SolidBrush(_DarkGray); 16 Pen penNode = new Pen(brushNode, 1f); 17 18 Brush brushNodeCompleted = new SolidBrush(_Blue); 19 Pen penNodeCompleted = new Pen(brushNodeCompleted, 1f); 20 21 22 int initX = 6; 23 //string 24 Font nFont = new Font("微软雅黑", 12); 25 Font stepFont = new Font("微软雅黑", 11,FontStyle.Bold); 26 int NodeNameWidth = 0; 27 28 foreach (var item in ListDataSource) 29 { 30 31 //round 32 33 Rectangle rec = new Rectangle(initX, CenterY - StepNodeWH / 2, StepNodeWH, StepNodeWH); 34 if (CurrentStep == item.StepOrder) 35 { 36 if (item.StepState == eumStepState.OutTime) 37 { 38 e.Graphics.DrawEllipse(new Pen(_Red,1f), rec); 39 e.Graphics.FillEllipse(new SolidBrush(_Red), rec); 40 } 41 else 42 { 43 e.Graphics.DrawEllipse(penNodeCompleted, rec); 44 e.Graphics.FillEllipse(brushNodeCompleted, rec); 45 } 46 47 //白色字体 48 SizeF fTitle = e.Graphics.MeasureString(index.ToString(), stepFont); 49 Point pTitle = new Point(initX + StepNodeWH / 2 - (int)Math.Round(fTitle.Width) / 2, CenterY - (int)Math.Round(fTitle.Height / 2)); 50 e.Graphics.DrawString(index.ToString(), stepFont, Brushes.White, pTitle); 51 52 53 //nodeName 54 SizeF sNode = e.Graphics.MeasureString(item.StepName, nFont); 55 Point pNode = new Point(initX + StepNodeWH, CenterY - (int)Math.Round(sNode.Height / 2) + 2); 56 57 e.Graphics.DrawString(item.StepName,new Font( nFont,FontStyle.Bold), brushNode, pNode); 58 NodeNameWidth = (int)Math.Round(sNode.Width); 59 if (index < count) 60 { 61 e.Graphics.DrawLine(p, initX + StepNodeWH + NodeNameWidth, CenterY, initX + StepNodeWH + NodeNameWidth + lineWidth, CenterY); 62 } 63 64 } 65 else if (item.StepOrder < CurrentStep) 66 { 67 //completed 68 e.Graphics.DrawEllipse(penNodeCompleted, rec); 69 //image 70 RectangleF recRF = new RectangleF(rec.X + 6, rec.Y + 6, rec.Width - 12, rec.Height - 12); 71 e.Graphics.DrawImage(ControlsResource.check_lightblue, recRF); 72 73 //nodeName 74 SizeF sNode = e.Graphics.MeasureString(item.StepName, nFont); 75 Point pNode = new Point(initX + StepNodeWH, CenterY - (int)Math.Round(sNode.Height / 2) + 2); 76 e.Graphics.DrawString(item.StepName, nFont, brushNode, pNode); 77 NodeNameWidth = (int)Math.Round(sNode.Width); 78 79 if (index < count) 80 { 81 e.Graphics.DrawLine(penNodeCompleted, initX + StepNodeWH + NodeNameWidth, CenterY, initX + StepNodeWH + NodeNameWidth + lineWidth, CenterY); 82 } 83 84 } 85 else 86 { 87 e.Graphics.DrawEllipse(p, rec); 88 // 89 SizeF fTitle = e.Graphics.MeasureString(index.ToString(), stepFont); 90 Point pTitle = new Point(initX + StepNodeWH / 2 - (int)Math.Round(fTitle.Width) / 2, CenterY - (int)Math.Round(fTitle.Height / 2)); 91 e.Graphics.DrawString(index.ToString(), stepFont, brush, pTitle); 92 //nodeName 93 SizeF sNode = e.Graphics.MeasureString(item.StepName, nFont); 94 Point pNode = new Point(initX + StepNodeWH, CenterY - (int)Math.Round(sNode.Height / 2) + 2); 95 e.Graphics.DrawString(item.StepName, nFont, brushNode, pNode); 96 NodeNameWidth = (int)Math.Round(sNode.Width); 97 if (index < count) 98 { 99 //line 100 e.Graphics.DrawLine(p, initX + StepNodeWH + NodeNameWidth, CenterY, initX + StepNodeWH + NodeNameWidth + lineWidth, CenterY); 101 } 102 } 103 104 //描述信息 105 if (item.StepDesc != "") 106 { 107 Point pNode = new Point(initX + StepNodeWH, CenterY+10); 108 e.Graphics.DrawString(item.StepDesc,new Font(nFont.FontFamily,10),brush, pNode); 109 } 110 111 112 113 index++; 114 //8 is space width 115 initX = initX + lineWidth + StepNodeWH+ NodeNameWidth+8; 116 } 117 } 118 }
控件的使用:
1 List<StepEntity> list = new List<StepEntity>(); 2 list.Add(new StepEntity("1", "新开单", 1, "这里是该步骤的描述信息", eumStepState.Completed, null)); 3 4 list.Add(new StepEntity("2", "主管审批", 2, "这里是该步骤的描述信息", eumStepState.Waiting, null)); 5 list.Add(new StepEntity("3", "总经理审批", 3, "这里是该步骤的描述信息", eumStepState.OutTime, null)); 6 list.Add(new StepEntity("2", "完成", 4, "这里是该步骤的描述信息", eumStepState.Waiting, null)); 7 8 this.stepViewer1.CurrentStep = 3; 9 this.stepViewer1.ListDataSource = list;
同样的,我们可以实现如下的timeline控件。