Linq的鍊式程式設計用起來總是那樣暢快淋漓,可惜在C#中并不是每時每刻都能有這麼暢快的感覺,其中使用Graphics的時候就是,每次用Graphics繪制大量圖形時尤其如此。GDI+的API功能很強大,但是在實際編碼中,很多重複性的工作總是讓我感覺到用起來很繁瑣,于是我就設計了這樣一個類庫,将C#中的Graphics類進行了二次封裝,讓其可以和Linq一樣,用起來“如沐春風”。
先來看一段簡單的示例代碼吧。下面代碼就是在一個窗體上繪制一系列圖形,可以看出和原來的Graphics相比,編碼量更小,代碼也更優雅。
1 private void Form1_Paint(object sender, PaintEventArgs e)
2 {
3 e.Graphics.Ex()
4 .DrawLine(10, 10, 50, 50)
5 .DrawLine(50, 50, 100, 50,Pens.Red)
6 .DrawLine(100, 50, 100, 100)
7 .DrawLine(100, 100, 150, 100, new Pen(Color.Blue,3f))
8 .DrawLine(150, 100, 150, 150)
9 .DrawRectangle(150, 50, 100, 100)
10 .FillRectangle(150, 50, 100, 100, Brushes.Red)
11 .DrawEllipse(150, 50, 50, 100, new Pen(Color.Yellow, 3f))
12 .FillEllipse(150, 50, 50, 100,Brushes.Green)
13 .DrawString("haha",new PointF(200f,200f))
14 .DrawString("leilei", new PointF(100f, 200f),new Font("微軟雅黑",30f));
15 }
畫出來的效果如下:
下面就是我對Graphics二次封裝的具體代碼,目前還隻能繪制Line、Rectangle、Ellipse和string
1 public static class GDIEx
2 {
3 public static GraphicsEx Ex(this Graphics g)
4 {
5 return new GraphicsEx(g);
6 }
7 }
8 public class GraphicsEx : IDisposable
9 {
10 readonly Graphics g;
11 Pen pen = Pens.Black;
12 Brush brush = Brushes.Black;
13 Font font = new Font(FontFamily.GenericSerif,10);
14 internal GraphicsEx(Graphics g)
15 {
16 this.g = g;
17 }
18 public void Dispose()
19 {
20 g.Dispose();
21 pen = null;
22 brush = null;
23 font = null;
24 }
25 public GraphicsEx DrawLine(int x1, int y1, int x2, int y2,[Optional]Pen pen)
26 {
27 if (pen != null)
28 this.pen = pen;
29 g.DrawLine(this.pen, x1, y1, x2, y2);
30 return this;
31 }
32 public GraphicsEx DrawLine(Point p1, Point p2,[Optional]Pen pen)
33 {
34 if (pen != null)
35 this.pen = pen;
36 g.DrawLine(this.pen, p1, p2);
37 return this;
38 }
39 public GraphicsEx DrawRectangle(Rectangle rect,[Optional]Pen pen)
40 {
41 if (pen != null)
42 this.pen = pen;
43 g.DrawRectangle(this.pen, rect);
44 return this;
45 }
46 public GraphicsEx DrawRectangle(int left,int top,int width,int height,[Optional]Pen pen)
47 {
48 if(pen != null)
49 this.pen = pen;
50 g.DrawRectangle(this.pen, left, top, width, height);
51 return this;
52 }
53 public GraphicsEx FillRectangle(Rectangle rect, [Optional]Brush brush)
54 {
55 if(brush != null)
56 this.brush = brush;
57 g.FillRectangle(this.brush, rect);
58 return this;
59 }
60 public GraphicsEx FillRectangle(int left, int top, int width, int height, [Optional]Brush brush)
61 {
62 if (brush != null)
63 this.brush = brush;
64 g.FillRectangle(this.brush, left, top, width, height);
65 return this;
66 }
67 public GraphicsEx DrawEllipse(Rectangle rect, [Optional]Pen pen)
68 {
69 if (pen != null)
70 this.pen = pen;
71 g.DrawEllipse(this.pen, rect);
72 return this;
73 }
74 public GraphicsEx DrawEllipse(int left, int top, int width, int height, [Optional]Pen pen)
75 {
76 if (pen != null)
77 this.pen = pen;
78 g.DrawEllipse(this.pen, left, top, width, height);
79 return this;
80 }
81 public GraphicsEx FillEllipse(Rectangle rect, [Optional]Brush brush)
82 {
83 if (brush != null)
84 this.brush = brush;
85 g.FillEllipse(this.brush, rect);
86 return this;
87 }
88 public GraphicsEx FillEllipse(int left, int top, int width, int height, [Optional]Brush brush)
89 {
90 if (brush != null)
91 this.brush = brush;
92 g.FillEllipse(this.brush, left, top, width, height);
93 return this;
94 }
95 public GraphicsEx DrawString(string str, RectangleF rect,[Optional]Font font, [Optional]Brush brush)
96 {
97 if (font != null)
98 this.font = font;
99 if (brush != null)
100 this.brush = brush;
101 g.DrawString(str, this.font, this.brush, rect);
102 return this;
103 }
104 public GraphicsEx DrawString(string str, PointF p, [Optional]Font font, [Optional]Brush brush)
105 {
106 if (font != null)
107 this.font = font;
108 if (brush != null)
109 this.brush = brush;
110 g.DrawString(str, this.font, this.brush, p);
111 return this;
112 }
113 }
封裝思想其實比較簡單,封裝的主體就是類GraphicsEx,該類根據構造函數中傳入的Graphics進行繪圖,并且繪制函數的簽名盡量和Graphics的接口保持一緻,以增加易用性,并且每個繪制函數都會傳回執行個體本身,以供不斷的調用。
所有的畫筆、畫刷或者其它與繪制内容無關的繪制參數都采用可選參數,這樣做的目的很簡單,從文章開始的示例中可以看出,在繪制一些Line的步驟中并沒有指明所用的畫筆,這時Graphics繪制時會自動采用上一次使用的畫筆或者初始畫筆進行繪制,這樣在使用同一種畫筆繪制多條直線,或者繪制多種不同圖形時,可以省去每一步都必須要指定畫筆的工作,減少編碼量。
我對GraphicsEx的構造函數通路級别進行了控制,設定為internal級别,隻讓其在程式集内可見,并且通過建構一個Graphics的擴充方法,用來建立GraphicsEx的執行個體,用來代替其本身構造函數的功能,這樣在使用時就顯得更加自然一些。
就寫這麼多了,不知道大家看完我這樣的封裝有什麼自己的看法,希望不吝賜教,在回帖中和我交流,謝謝!