最近這段時間,公司須要作一個圖形化配置工具。html
主要是有如下一些要求:框架
一、針對一些底層的智能設備(智能樓宇的控制器),經過COM口鏈接上,並經過相關協議讀取參數值ide
二、支持一些基本的邏輯運算,以及公司業務的一些特性「點」,一種點能夠當作一個圖形化控件工具
三、參數在圖形化工具上顯示出來,工程人員直接設置圖形屬性設置參數值、連線等測試
四、支持在線和離線2種工做方式,設置好參數後直接在界面上下載到設備裏字體
五、工做太支持拖動,連線,放大縮小,保存設計文件等this
六、「點」的自己業務要求,略。。。設計
通過一番調研,winfrom的圖形化控件技術,並無成熟的框架出來。htm
只有一些零碎的demo,大致上的思路是經過重繪來實現具體的圖形控件。對象
在這裏也提一下Netron框架,這個框架代碼我看了不少遍,不少思路都從這裏來,可是太繁瑣了,改動起來很是吃力
因此我本身從新寫了一遍,大致思路沒變,只是走精簡路線,如下是咱們的工具最終的界面樣式,
我打算把每一步都分拆貼出來,作成一個教程。給你們一個參考
1.1 包含一些基本屬性,如字體、是否懸停、是否選中、畫布
1.2 包含幾個抽象方法,繪製控件皮膚、移動、懸停判斷、從新繪製
public abstract class AbstractShape { [Browsable(false)] public Font DefaultFont { get; private set; } [Browsable(false)] public Pen DefaultPen { get; private set; } [Browsable(false)] public bool IsHover { get; set; } [Browsable(false)] public bool IsSelected { get; set; } [Browsable(false)] public GraphControl Canvas { get; set; } public AbstractShape() { } public AbstractShape(GraphControl site) { DefaultFont = new Font("宋體", 10F); DefaultPen = new Pen(Brushes.Black, 1F); Canvas = site; IsHover = false; IsSelected = false; } public abstract void Paint(Graphics g); public abstract bool Hover(Point p); public abstract void Invalidate(); public abstract void Move(Point p); }
包含一些基本屬性及一些共性方法實現
public class ShapeBase : AbstractShape { protected Rectangle RectangleBase; [Browsable(false)] public Brush ShapeBrush { get; protected set; } [Browsable(true), Description("Width"), Category("Layout")] public int Width { get { return this.RectangleBase.Width; } set { Resize(value, this.Height); } } [Browsable(true), Description("Height"), Category("Layout")] public int Height { get { return this.RectangleBase.Height; } set { Resize(this.Width, value); } } [Browsable(true), Description("X"), Category("Layout")] public int X { get { return RectangleBase.X; } set { Point p = new Point(value - RectangleBase.X, RectangleBase.Y); this.Move(p); Canvas.Invalidate(); } } [Browsable(true), Description("Y"), Category("Layout")] public int Y { get { return RectangleBase.Y; } set { Point p = new Point(RectangleBase.X, value - RectangleBase.Y); this.Move(p); Canvas.Invalidate(); } } [Browsable(true), Description("Text"), Category("Layout")] public string Text { get; set; } public ShapeBase(GraphControl site) : base(site) { Init(); } private void Init() { RectangleBase = new Rectangle(0, 0, 100, 70); ShapeBrush = new SolidBrush(Color.SteelBlue); } public override void Paint(Graphics g) { return; } public override bool Hover(Point p) { return false; } public override void Invalidate() { Canvas.Invalidate(RectangleBase); } public override void Move(Point p) { this.RectangleBase.X += p.X; this.RectangleBase.Y += p.Y; } public virtual void Resize(int width, int height) { this.RectangleBase.Height = height; this.RectangleBase.Width = width; } }
public class LjrRectangle : ShapeBase { public LjrRectangle(GraphControl s) : base(s) { } public override void Paint(Graphics g) { g.FillRectangle(base.ShapeBrush, base.RectangleBase); if (base.IsHover || base.IsSelected) { g.DrawRectangle(new Pen(Color.Red, 2F), base.RectangleBase); } else { g.DrawRectangle(base.DefaultPen, base.RectangleBase); } } }
因此自定義圖形控件都將在這個畫布裏繪製、移動等操做
public class GraphControl : ScrollableControl { /// <summary>屬性控件綁定事件</summary> public delegate void ShowProperty(object ent); /// <summary>屬性控件綁定事件</summary> public event ShowProperty OnShowProperty; /// <summary>當前懸停在哪一個對象上邊</summary> protected AbstractShape hoveredObject; /// <summary>當前選中的對象</summary> protected AbstractShape selectedObject; /// <summary>是否正在拖動</summary> protected bool draging = false; /// <summary>圖形對象集合</summary> public List<ShapeBase> Shapes { get; set; } public GraphControl() { Shapes = new List<ShapeBase>(); } protected override void OnPaintBackground(PaintEventArgs e) { base.OnPaintBackground(e); Graphics g = e.Graphics; Size gridSize = new Size(10, 10); ControlPaint.DrawGrid(g, this.ClientRectangle, gridSize, this.BackColor); } protected override void OnPaint(PaintEventArgs e) { Graphics g = e.Graphics; g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias; for (int k = 0; k < Shapes.Count; k++) { Shapes[k].Paint(g); } } public ShapeBase AddShape(ShapeBase shape) { Shapes.Add(shape); shape.Canvas = this; this.Invalidate(); return shape; } }
5.1 新建demo.cs把控件拖入界面左邊
5.2 再拖一個PropertyGrid用來顯示屬性值
5.3 Demo.cs代碼以下
private void Demo_Load(object sender, EventArgs e) { var shape = new LjrRectangle(graphControl1); shape.Location = new Point(100, 300); shape.Text = "圖形化控件"; this.graphControl1.AddShape(shape); this.graphControl1.OnShowProperty += graphControl1_OnShowProps; } private void graphControl1_OnShowProps(object ent) { this.propertyGrid1.SelectedObject = ent; }