最近這段時間,公司需要做一個圖形化配置工具。
主要是有以下一些要求:
1、針對一些底層的智能設備(智能樓宇的控制器),通過COM口連接上,並通過相關協議讀取參數值
2、支持一些基本的邏輯運算,以及公司業務的一些特性“點”,一種點可以看成一個圖形化控件
3、參數在圖形化工具上顯示出來,工程人員直接設置圖形屬性設置參數值、連線等
4、支持在線和離線2種工作方式,設置好參數后直接在界面上下載到設備里
5、工作太支持拖動,連線,放大縮小,保存設計文件等
6、“點”的本身業務要求,略。。。
經過一番調研,winfrom的圖形化控件技術,並沒有成熟的框架出來。
只有一些零碎的demo,大體上的思路是通過重繪來實現具體的圖形控件。
在這里也提一下Netron框架,這個框架代碼我看了很多遍,很多思路都從這里來,但是太繁瑣了,改動起來非常吃力
所以我自己重新寫了一遍,大體思路沒變,只是走精簡路線,以下是我們的工具最終的界面樣式,
我打算把每一步都分拆貼出來,做成一個教程。給大家一個參考

1、新建自定義控件抽象類
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);
}
2、繪制一個自定義控件基類
包含一些基本屬性及一些共性方法實現
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;
}
}
3、新建一個簡單的矩形類
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);
}
}
}
4、新建畫布GraphControl
所以自定義圖形控件都將在這個畫布里繪制、移動等操作
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、新建測試項目
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;
}
6、運行程序

閱讀目錄
- 圖形化控件開發 - 矩形控件
- 圖形化控件開發 - 控件移動
- 圖形化控件開發 - 直線連線
- 圖形化控件開發 - 折線連線
- 圖形化控件開發 - 放大縮小
- 圖形化控件開發 - 待定
