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的實例,用來代替其本身構造函數的功能,這樣在使用時就顯得更加自然一些。
就寫這么多了,不知道大家看完我這樣的封裝有什么自己的看法,希望不吝賜教,在回帖中和我交流,謝謝!
