WinForm(三)揭開視覺化控制元件的面紗
阿新 • • 發佈:2022-12-10
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的感覺。
想要更快更方便的瞭解相關知識,可以關注微信公眾號