WinForm所見即所得的UI設計框架,開發效率確實有所提升,同時降低了編程門檻,讓WinForm更普及。拖拖拽拽就能設計出一個界面,那么我們拖拽的這些東西是什么?它們是什么原理?。
WinForm我覺得很好的一點是,把所有東西都對像化(畢竟C#是面向對象的語言),包括可視化的窗體,控件等,當然有的控件在運行時是能看見的,比如按鈕,文本框,下拉列表框等等,還有一類是在運時看不見的,比如Timers,FileSystemWatcher等。這些全都構建成了對象,那么看得見的控件是怎么看得見的呢?答案是繪制出來的,畫出來才能看得見。是用GDI+技術畫出來的。
為了能夠讓大家更深入的理解,我們現在畫一個Switch控件,Switch是蘋果體系里的控件,在WinForm中,系統控件是沒有的。Switch的作用非常像CheckBox,所以我們就參照CheckBoxRenderer來畫,只不過畫的形狀不一樣,具體代碼如下:
using System;
using System.Collections.Generic;
using System.Drawing.Drawing2D;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms.VisualStyles;namespace WinFormDemo02
{public class Switch : Control{private Rectangle textRectangleValue = new Rectangle();private?CheckBoxState?state?=?CheckBoxState.UncheckedNormal;public?Switch():?base(){this.Location = new Point(50, 50);this.Size = new Size(50, 25);this.Font = SystemFonts.IconTitleFont;DoubleBuffered = true;SetStyle(ControlStyles.OptimizedDoubleBuffer |ControlStyles.ResizeRedraw |ControlStyles.AllPaintingInWmPaint, true);}public bool Checked{get; set;} = false;void DrawSwitch(Graphics g){var x = 0;var y = 0;var width = 25;g.SmoothingMode = SmoothingMode.HighQuality;g.PixelOffsetMode = PixelOffsetMode.HighQuality;g.InterpolationMode = InterpolationMode.High;g.CompositingQuality = CompositingQuality.HighQuality;SolidBrush brush;if (Checked){brush = new SolidBrush(Color.MediumSeaGreen);}else{brush = new SolidBrush(Color.DarkRed);}g.FillPie(brush, new Rectangle(x, y, width, width), 90, 180);g.FillRectangle(brush,?new?Rectangle(x?+?width?/?2?-?1,?y,?width,?width));g.FillPie(brush,?new?Rectangle(x?+?width?-?2,?y,?width,?width),?-90,?180);if?(Checked){var selectBrush = new SolidBrush(Color.White);g.FillEllipse(selectBrush, new Rectangle(x + 2, y + 2, width - 4, width - 4));}else{var selectBrush = new SolidBrush(Color.White);g.FillEllipse(selectBrush, new Rectangle(x + width, y + 2, width - 4, width - 4));}}public Rectangle TextRectangle{get{using (Graphics g = this.CreateGraphics()){textRectangleValue.X = ClientRectangle.X +CheckBoxRenderer.GetGlyphSize(g,CheckBoxState.UncheckedNormal).Width;textRectangleValue.Y = ClientRectangle.Y;textRectangleValue.Width = ClientRectangle.Width -CheckBoxRenderer.GetGlyphSize(g,CheckBoxState.UncheckedNormal).Width;textRectangleValue.Height = ClientRectangle.Height;}return textRectangleValue;}}protected override void OnPaint(PaintEventArgs e){DrawSwitch(e.Graphics);base.OnPaint(e);}public event EventHandler CheckedChanged;protected override void OnMouseDown(MouseEventArgs e){base.OnMouseDown(e);if (!Checked){Checked = true;state = CheckBoxState.CheckedPressed;Invalidate();}else{Checked = false;state = CheckBoxState.UncheckedNormal;Invalidate();}CheckedChanged(this,new EventArgs());}protected override void OnMouseHover(EventArgs e){base.OnMouseHover(e);state = Checked ? CheckBoxState.CheckedHot :CheckBoxState.UncheckedHot;Invalidate();}protected override void OnMouseUp(MouseEventArgs e){base.OnMouseUp(e);this.OnMouseHover(e);}protected override void OnMouseLeave(EventArgs e){base.OnMouseLeave(e);state = Checked ? CheckBoxState.CheckedNormal :CheckBoxState.UncheckedNormal;Invalidate();}}
}
我只是簡單的實現了一下,重點在DrawSwitch這個方法,就是畫兩個半圓,中間是一個正方形,然后在上面畫一個白圓,根據Checked屬性,最上面的白圓在兩邊切換,僅此而以。
看一下運行結果吧(自行點擊播放):
通過上面例子,不知你是否了解了可視化控件的實現方式。如果你是初學者,完整的思路不太通,沒關系,理解到控件是畫出來的就夠了,后面應該會說到GDI+的詳細技術點。如果你是WinForm老手,可以自己實現一套自己的專用控件,把Window上的應用Run出Mac的感覺,甚至IOS的感覺。