当前位置: 首页 > news >正文

C#绘制常用工业控件(仪表盘,流动条,开关等)

目录

1,使用Graphics绘制Toggle。

效果:

测试代码:

Toggle控件代码:

2,使用Graphics绘制Switch。

效果:

测试代码:

Switch控件代码:

3,使用Graphics绘制PanelHead。

效果

PanelHead控件代码:

4,自定义数字键盘NumberKeyBoard。

效果:

测试代码:

NumberKeyBoard控件代码

5,使用Graphics绘制LED。

效果:

LED控件代码:

6,使用Graphics绘制流动条。

效果:

FlowControl代码 :

7,使用Graphics绘制仪表盘1:

效果:

DashBoard控件代码

8,使用Graphics绘制仪表盘2:

效果:

Gague控件代码:


预览

1,使用Graphics绘制Toggle。

效果:

测试代码:
 private void toggle3_Click(object sender, EventArgs e){toggle3.Checked = !toggle3.Checked;}private void toggle2_Click(object sender, EventArgs e){toggle2.Checked = !toggle2.Checked;}private void toggle1_Click(object sender, EventArgs e){toggle1.Checked = !toggle1.Checked;}
Toggle控件代码:
 [DefaultEvent("Click")]//指定默认事件public partial class Toggle : UserControl{public Toggle(){InitializeComponent();设置控件样式this.SetStyle(ControlStyles.AllPaintingInWmPaint, true);this.SetStyle(ControlStyles.DoubleBuffer, true);this.SetStyle(ControlStyles.ResizeRedraw, true);this.SetStyle(ControlStyles.Selectable, true);this.SetStyle(ControlStyles.SupportsTransparentBackColor, true);this.SetStyle(ControlStyles.UserPaint, true);}string falseText = "关闭";[Browsable(true), Category("自定义属性"), Description("false时文本")]public string FalseText{get{return falseText;}set{falseText = value;this.Invalidate();}}string trueText = "打开";[Browsable(true), Category("自定义属性"), Description("true时文本")]public string TrueText{get{return trueText;}set{trueText = value;this.Invalidate();}}bool _checked = false;[Browsable(true), Category("自定义属性"), Description("是否确认,Ture表示ON,False表示OFF")]public bool Checked{get{return _checked;}set{_checked = value;this.Invalidate();}}bool isShowWord = false;[Browsable(true), Category("自定义属性"), Description("是否显示文字,如果否则显示形状")]public bool IsShowWord{get{return isShowWord;}set{isShowWord = value;this.Invalidate();}}Color falseColor = Color.LightGray;[Browsable(true), Category("自定义属性"), Description("False状态时填充色")]public Color FalseColor{get{return falseColor;}set{falseColor = value;this.Invalidate();}}Color trueColor = Color.CadetBlue;[Browsable(true), Category("自定义属性"), Description("True状态时填充色")]public Color TrueColor{get{return trueColor;}set{trueColor = value;this.Invalidate();}}[Browsable(true), Category("自定义属性"), Description("若为非文字模式时,圆点的半径")]public int EmbellishRadius{get{return (int)(EmbellishRadiusFactor * Height);}}float _embellishRadiusFactor = 0.15f;[Browsable(true), Category("自定义属性"), Description("若为非文字模式时,圆点的比例因子")]public float EmbellishRadiusFactor{set{if (value >= 1 || value <= 0){_embellishRadiusFactor = 0.3f;}else{_embellishRadiusFactor = value;}this.Invalidate();}get{return _embellishRadiusFactor;}}bool _embellishPointAuto = true;[Browsable(true), Category("自定义属性"), Description("修饰文字或者图形的起点是否自动获取")]public bool EmbellishPointAuto{get{return _embellishPointAuto;}set{_embellishPointAuto = value;this.Invalidate();}}PointF _embellishPoint;[Browsable(true), Category("自定义属性"), Description("绘制修饰文字或者图形所需的起点")]public PointF EmbellishPoint{get{return _embellishPoint;}set{_embellishPoint = value;if (!EmbellishPointAuto){this.Invalidate();}}}Color _embellishColor = Color.White;[Browsable(true), Category("自定义属性"), Description("绘制修饰文字或者图形所需的颜色")]public Color EmbellishColor{get{return _embellishColor;}set{_embellishColor = value;this.Invalidate();}}ToggleType _toggleType = ToggleType.Rectangle;[Browsable(true), Category("自定义属性"), Description("Toggle的样式")]public ToggleType ToggleStyle{get{return _toggleType;}set{_toggleType = value;this.Invalidate();}}Padding _borderRadius = new Padding(3);[Browsable(true), Category("自定义属性"), Description("Rectangle风格时采用的倒角半径")]public Padding BorderRadius{get{return _borderRadius;}set{_borderRadius = value;if (ToggleStyle == ToggleType.Rectangle){this.Invalidate();}}}int _innerGap = 3;[Browsable(true), Category("自定义属性"), Description("内部间隙")]public int InnerGap{get{return _innerGap;}set{_innerGap = value;this.Invalidate();}}Color _slidingColor = Color.White;[Browsable(true), Category("自定义属性"), Description("滑动块颜色")]public Color SlidingColor{get{return _slidingColor;}set{_slidingColor = value;this.Invalidate();}}protected override void OnPaint(PaintEventArgs e){base.OnPaint(e);Graphics g = e.Graphics;g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;g.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighQuality;g.TextRenderingHint = System.Drawing.Text.TextRenderingHint.ClearTypeGridFit;GraphicsPath path = new GraphicsPath();Padding drawingRadius;if (ToggleStyle == ToggleType.Ellipse){drawingRadius = new Padding(Height / 2);}else{drawingRadius = BorderRadius;}//绘制矩形//左上角path.AddArc(0, 0, drawingRadius.Left * 2, drawingRadius.Left * 2, 180, 90);//右上角path.AddArc(Width - drawingRadius.Top * 2, 0, drawingRadius.Top * 2, drawingRadius.Top * 2, 270, 90);//右下角path.AddArc(Width - drawingRadius.Right * 2, Height - drawingRadius.Right * 2, drawingRadius.Right * 2, drawingRadius.Right * 2, 0, 90);//左下角path.AddArc(0, Height - 2 * drawingRadius.Bottom, 2 * drawingRadius.Bottom, 2 * drawingRadius.Bottom, 90, 90);//滑动块起点Point slidingPoint;if (Checked){g.FillPath(new SolidBrush(TrueColor), path);slidingPoint = new Point(Width - Height + InnerGap, InnerGap);//如果是文字模式if (IsShowWord && EmbellishPointAuto){SizeF trueTextSize = g.MeasureString(TrueText, this.Font);EmbellishPoint = new PointF(((Width - trueTextSize.Width - Height)) / 2, ((Height - trueTextSize.Height)) / 2);}//如果是非文字模式if (!IsShowWord && EmbellishPointAuto){EmbellishPoint = new PointF(Height / 2 - EmbellishRadius, Height / 2 - EmbellishRadius);}}else{g.FillPath(new SolidBrush(FalseColor), path);slidingPoint = new Point(InnerGap, InnerGap);//如果是文字模式if (IsShowWord && EmbellishPointAuto){SizeF falseTextSize = g.MeasureString(FalseText, this.Font);EmbellishPoint = new PointF(Height + (Width - Height - falseTextSize.Width) / 2, ((Height - falseTextSize.Height)) / 2);}//如果是非文字模式if (!IsShowWord && EmbellishPointAuto){EmbellishPoint = new Point(Width - (Height / 2 + EmbellishRadius / 2), Height / 2 - EmbellishRadius);}}int slidingWidth = Height - 2 * InnerGap;GraphicsPath path2 = new GraphicsPath(FillMode.Alternate);int slidingHeight = slidingWidth;float scale = slidingWidth * 1.0f / Width;if (ToggleStyle == ToggleType.Rectangle){//左上角path2.AddArc(slidingPoint.X, slidingPoint.Y, drawingRadius.Left * 2, drawingRadius.Left * 2, 180, 90);//右上角path2.AddArc(slidingPoint.X + slidingWidth - drawingRadius.Top * 2, slidingPoint.Y, drawingRadius.Top * 2, drawingRadius.Top * 2, 270, 90);//右下角path2.AddArc(slidingPoint.X + slidingWidth - drawingRadius.Right * 2, slidingPoint.Y + slidingHeight - drawingRadius.Right * 2, drawingRadius.Right * 2, drawingRadius.Right * 2, 0, 90);//左下角path2.AddArc(slidingPoint.X, slidingPoint.Y + slidingHeight - 2 * drawingRadius.Bottom, 2 * drawingRadius.Bottom, 2 * drawingRadius.Bottom, 90, 90);}else{path2.AddEllipse(slidingPoint.X, slidingPoint.Y, Height - 2 * InnerGap, Height - 2 * InnerGap);}g.FillPath(new SolidBrush(SlidingColor), path2);if (IsShowWord){if (Checked){g.DrawString(TrueText, this.Font, new SolidBrush(this.EmbellishColor), EmbellishPoint);}else{g.DrawString(FalseText, this.Font, new SolidBrush(this.EmbellishColor), EmbellishPoint);}}else{g.DrawEllipse(new Pen(EmbellishColor, 2), new RectangleF(EmbellishPoint, new SizeF(EmbellishRadius * 2, EmbellishRadius * 2)));}}}public enum ToggleType{/// <summary>/// 矩形形状/// </summary>Rectangle,/// <summary>/// 椭圆形状/// </summary>Ellipse}

2,使用Graphics绘制Switch。

效果:

测试代码:
 private void switchControl1_Click(object sender, EventArgs e){switchControl1.SwitchStatus = !switchControl1.SwitchStatus;}
Switch控件代码:
 [DefaultEvent("Click")]public partial class SwitchControl : UserControl{public SwitchControl(){InitializeComponent();设置控件样式this.SetStyle(ControlStyles.AllPaintingInWmPaint, true);this.SetStyle(ControlStyles.DoubleBuffer, true);this.SetStyle(ControlStyles.ResizeRedraw, true);this.SetStyle(ControlStyles.Selectable, true);this.SetStyle(ControlStyles.SupportsTransparentBackColor, true);this.SetStyle(ControlStyles.UserPaint, true);}int _outGap = 20;/// <summary>/// 外间隙/// </summary>[Browsable(true),Category("自定义属性"),Description("外间隙")]public int OutCap{get{return _outGap;}set{if (_outGap < 0){_outGap = 0;}else{_outGap = value;}this.Invalidate();}}int _innerGap = 3;/// <summary>/// 内间隙/// </summary>[Browsable(true), Category("自定义属性"), Description("内间隙")]public int InnerCap{get{return _innerGap;}set{if (_innerGap < 0){_innerGap = 0;}else{_innerGap = value;}this.Invalidate();}}bool _switchStatus = false;/// <summary>/// 开关状态/// </summary>[Browsable(true), Category("自定义属性"), Description("开关状态")]public bool SwitchStatus{get{return _switchStatus;}set{_switchStatus = value;this.Invalidate();}}int _outCircleWidth = 4;/// <summary>/// 外圆宽度/// </summary>[Browsable(true), Category("自定义属性"), Description("外圆宽度")]public int OutCircleWidth{get{return _outCircleWidth;}set{if (_outCircleWidth < 0){_outCircleWidth = 2;}else{_outCircleWidth = value;}this.Invalidate();}}Color _outCircleColor = Color.Gray;/// <summary>/// 外圆颜色/// </summary>[Browsable(true), Category("自定义属性"), Description("外圆颜色")]public Color OutCircleColor{get{return _outCircleColor;}set{_outCircleColor = value;this.Invalidate();}}Color _innerCircleColor = Color.Gray;/// <summary>/// 外圆颜色/// </summary>[Browsable(true), Category("自定义属性"), Description("内圆颜色")]public Color InnerCircleColor{get{return _innerCircleColor;}set{_innerCircleColor = value;this.Invalidate();}}/// <summary>///旋转手柄宽度/// </summary>[Browsable(true), Category("自定义属性"), Description("旋转手柄宽度")]public float HandleWidth{get{return Dimensions*HandleWidthFactor;}}float _handleWidthFactor = 0.1f;/// <summary>///旋转手柄宽度比例因子/// </summary>[Browsable(true), Category("自定义属性"), Description("旋转手柄宽度比例因子")]public float HandleWidthFactor{get{return _handleWidthFactor;}set{if (_handleWidthFactor < 0){_handleWidthFactor = 0.15f;}else{_handleWidthFactor = value;}this.Invalidate();}}Color _embellishColor = Color.Orange;/// <summary>/// 手柄标记颜色/// </summary>[Browsable(true), Category("自定义属性"), Description("手柄标记颜色")]public Color EmbellishColor{get{return _embellishColor;}set{_embellishColor = value;this.Invalidate();}}Color _handleColor = Color.Black;/// <summary>/// 手柄颜色/// </summary>[Browsable(true), Category("自定义属性"), Description("手柄颜色")]public Color HandleColor{get{return _handleColor;}set{_handleColor = value;this.Invalidate();}}/// <summary>/// 绘图的标准尺寸/// </summary>private int Dimensions{get{if (Width > Height){return Height;}else{return Width;}}}float _sweep = 36;/// <summary>/// 手柄旋转角度/// </summary>[Browsable(true), Category("自定义属性"), Description("手柄旋转角度")]public float Sweep{get{return _sweep;}set{_sweep = value;this.Invalidate();}}protected override void OnPaint(PaintEventArgs e){base.OnPaint(e);Graphics g = e.Graphics;g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;g.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighQuality;g.TextRenderingHint = System.Drawing.Text.TextRenderingHint.ClearTypeGridFit;//绘制外圆g.DrawEllipse(new Pen(OutCircleColor, OutCircleWidth), OutCap, OutCap, this.Dimensions - 2 * OutCap, Dimensions - 2 * OutCap);//绘制内圆Point innerPoint = new Point(OutCap + OutCircleWidth + InnerCap, OutCap + OutCircleWidth + InnerCap);int innerWidth = Dimensions - 2 * innerPoint.X ;g.FillEllipse(new SolidBrush(InnerCircleColor), innerPoint.X, innerPoint.Y, innerWidth, innerWidth);//偏移原点g.TranslateTransform(Dimensions / 2, Dimensions / 2);//旋转角度if (SwitchStatus){g.RotateTransform(Sweep);}else{g.RotateTransform(-Sweep);}//绘制手柄g.FillRectangle(new SolidBrush(HandleColor), -HandleWidth/2, (-Dimensions + OutCap)/2, HandleWidth, Dimensions - OutCap);//绘制手柄标志float embellishWidth = HandleWidth / 2;float embellishHeight = HandleWidth * 1.5f;g.FillEllipse(new SolidBrush(EmbellishColor), -embellishWidth / 2, (-Dimensions + OutCap) / 2 + embellishWidth / 2, embellishWidth, embellishHeight);}}

3,使用Graphics绘制PanelHead。

效果

可设置边框颜色,有无,Header文字,Header高度,背景色等,以及Dock类型

PanelHead控件代码:
public partial class PanelHead : Panel{public PanelHead(){InitializeComponent();//  设置控件样式this.SetStyle(ControlStyles.AllPaintingInWmPaint, true);this.SetStyle(ControlStyles.DoubleBuffer, true);this.SetStyle(ControlStyles.ResizeRedraw, true);this.SetStyle(ControlStyles.Selectable, true);this.SetStyle(ControlStyles.SupportsTransparentBackColor, true);this.SetStyle(ControlStyles.UserPaint, true);}private Color _headerBackgroundColor = Color.SkyBlue;[Browsable(true), Category("自定义属性"), Description("Header背景色")]public Color HeaderBackgroundColor{get { return _headerBackgroundColor; }set{_headerBackgroundColor = value;this.Invalidate();}}private int _headerHeight = 40;[Browsable(true), Category("自定义属性"), Description("Header高度")]public int HeaderHeight{get { return _headerHeight; }set{_headerHeight = value;this.Invalidate();}}private Color _headerForeColor = Color.Black;[Browsable(true), Category("自定义属性"), Description("Header前景色")]public Color HeaderForeColor{get { return _headerForeColor; }set{_headerForeColor = value;this.Invalidate();}}private string _headerText="标题";[Browsable(true), Category("自定义属性"), Description("Header前景色")]public string HeaderText{get { return _headerText; }set{_headerText = value;this.Invalidate();}}private Font _headerFont = DefaultFont;[Browsable(true), Category("自定义属性"), Description("Header文字字体")]public Font HeaderFont{get { return _headerFont; }set{_headerFont = value;this.Invalidate();}}private StringAlignment _headerTextAlignment = StringAlignment.Center;[Browsable(true), Category("自定义属性"), Description("Header文字水平对齐方式")]public StringAlignment HeaderTextAlignment{get { return _headerTextAlignment; }set{_headerTextAlignment = value;this.Invalidate();}}private StringAlignment _headerTextLineAlignment = StringAlignment.Center;[Browsable(true), Category("自定义属性"), Description("Header文字垂直对齐方式")]public StringAlignment HeaderTextLineAlignment{get { return _headerTextLineAlignment; }set{_headerTextLineAlignment = value;this.Invalidate();}}private bool _hasBorder = true;[Browsable(true), Category("自定义属性"), Description("是否有外边框")]public bool HasBorder{get { return _hasBorder; }set{_hasBorder = value;this.Invalidate();}}private Color _borderColor = Color.Black;[Browsable(true), Category("自定义属性"), Description("外边框颜色")]public Color BorderColor{get { return _borderColor; }set{_borderColor = value;this.Invalidate();}}private int _borderWidth = 1;[Browsable(true), Category("自定义属性"), Description("外边框的宽度")]public int BorderWidth{get { return _borderWidth; }set{_borderWidth = value;this.Invalidate();}}protected override void OnPaint(PaintEventArgs e){base.OnPaint(e);Graphics g = e.Graphics;g.SmoothingMode = SmoothingMode.AntiAlias; //使绘图质量最高,即消除锯齿g.InterpolationMode = InterpolationMode.HighQualityBicubic;g.CompositingQuality = CompositingQuality.HighQuality;g.FillRectangle(new SolidBrush(HeaderBackgroundColor), OriginPoint.X, OriginPoint.Y, DimensionsWidth, HeaderHeight);StringFormat format = new StringFormat(){Alignment = this.HeaderTextAlignment,LineAlignment = HeaderTextLineAlignment};g.DrawString(HeaderText, HeaderFont, new SolidBrush(HeaderForeColor), new RectangleF(OriginPoint.X, OriginPoint.Y, DimensionsWidth, HeaderHeight), format);//绘制边框if (HasBorder){g.DrawRectangle(new Pen(BorderColor, BorderWidth), BorderWidth / 2, BorderWidth / 2, Width - BorderWidth, Height - BorderWidth);}}int DimensionsWidth{get{if (HasBorder){return Width - BorderWidth-2;}return Width;}}int DimensionsHeight{get{if (HasBorder){return Height - BorderWidth-2;}return Height;}}Point OriginPoint{get{if (HasBorder){return new Point(BorderWidth, BorderWidth);}return new Point(0, 0);}}Dictionary<Control, Rectangle> dic = new Dictionary<Control, Rectangle>();int flag = 0xff;protected override void OnLayout(LayoutEventArgs e){if (HasChildren){foreach (Control item in this.Controls){switch (item.Dock){case DockStyle.None:item.SuspendLayout();if (dic.ContainsKey(item) && !((flag & 0x1) == 1)){item.Bounds = dic[item];flag = 0xff;}item.ResumeLayout();//  base.OnLayout(e);break;case DockStyle.Top:if ((flag & 0x1) == 1){dic[item] = item.Bounds;flag = flag & 0xfe;}if ((flag & 0x2) == 2){item.Bounds = dic[item];flag = flag & 0xfd;}item.SuspendLayout();if (item.Height <= DimensionsHeight - HeaderHeight){item.SetBounds(OriginPoint.X, OriginPoint.Y + HeaderHeight, DimensionsWidth, item.Height);}else{item.SetBounds(OriginPoint.X, OriginPoint.Y + HeaderHeight, DimensionsWidth, DimensionsHeight - HeaderHeight);}break;case DockStyle.Bottom:if ((flag & 0x1) == 1){dic[item] = item.Bounds;flag = flag & 0xfe;}if ((flag & 0x4) == 4){item.Bounds = dic[item];flag = flag & 0xfb;}item.SuspendLayout();if (item.Height <= DimensionsHeight - HeaderHeight){item.SetBounds(OriginPoint.X,OriginPoint.Y+ DimensionsHeight -item.Height, DimensionsWidth, item.Height);}else{item.SetBounds(OriginPoint.X, OriginPoint.Y + HeaderHeight, DimensionsWidth, DimensionsHeight - HeaderHeight);}break;case DockStyle.Left:if ((flag & 0x1) == 1){dic[item] = item.Bounds;flag = flag & 0xfe;}if ((flag & 0x8) == 8){item.Bounds = dic[item];flag = flag & 0xf7;}item.SuspendLayout();if (item.Width <= DimensionsWidth){item.SetBounds(OriginPoint.X, OriginPoint.Y + HeaderHeight, item.Width, DimensionsHeight - HeaderHeight);}else{item.SetBounds(OriginPoint.X, OriginPoint.Y + HeaderHeight, DimensionsWidth, Height - HeaderHeight);}break;case DockStyle.Right:if ((flag & 0x1) == 1){dic[item] = item.Bounds;flag = flag & 0xfe;}if ((flag & 0x10) == 16){item.Bounds = dic[item];flag = flag & 0xef;}item.SuspendLayout();if (item.Width <= DimensionsWidth){item.SetBounds(OriginPoint.X + DimensionsWidth - item.Width, OriginPoint.Y + HeaderHeight, item.Width, DimensionsHeight - HeaderHeight);}else{item.SetBounds(OriginPoint.X, OriginPoint.Y + HeaderHeight, DimensionsWidth, Height - HeaderHeight);}break;case DockStyle.Fill:if ((flag & 0x1) == 1){dic[item] = item.Bounds;flag = flag & 0xfe;}item.SuspendLayout();item.SetBounds(OriginPoint.X, OriginPoint.Y + HeaderHeight, DimensionsWidth, DimensionsHeight - HeaderHeight);break;default:break;}}}}}

4,自定义数字键盘NumberKeyBoard。

效果:

测试代码:
public Form2(){InitializeComponent();//接收输入完成的数据numKeyBoard1.InputCompleted += NumKeyBoard1_InputCompleted1;//Esc事件numKeyBoard1.InputCancel += NumKeyBoard1_InputCancel;}private void Form2_Load(object sender, EventArgs e){//注册哪些控件使用数字键盘,通过控件名进行注册,如果不注册将无数字键盘弹出numKeyBoard1.RegisterNumberKeyBoard(new string[] { "textBox1", "textBox2", "textBox3" });}private void NumKeyBoard1_InputCancel(object sender, EventArgs e){//键盘的打开是通过目的控件的GotFocus事件完成如果不将焦点转移到其他控件,将影响在该目的控件上重复打开键盘this.ActiveControl = button1;}private void NumKeyBoard1_InputCompleted1(object sender, CustomControl.NumKeyBoardEventArgs e){Control control = e.TargetControl;float value = e.Value;if(control is TextBox){control.Text = value.ToString();}this.ActiveControl=button1;}
NumberKeyBoard控件代码

 public partial class NumKeyBoard : UserControl{public NumKeyBoard(){InitializeComponent();InitLoad();}/// <summary>/// 数字键盘输入完成/// </summary>public event EventHandler<NumKeyBoardEventArgs> InputCompleted;/// <summary>/// 输入取消事件/// </summary>public event EventHandler InputCancel;List<Control> targetControls = new List<Control>();void InitLoad(){lblTitle.MouseMove += NumKeyBoard_MouseMove;lblTitle.MouseDown += NumKeyBoard_MouseDown;lblTitle.MouseUp += NumKeyBoard_MouseUp;foreach (Control item in tableLayoutKeyBoard.Controls){if (item is Button){(item as Button).Click += NumKeyBoard_Click;}}}Control curControl;private void TargetControl_GotFocus(object sender, EventArgs e){this.Visible = true;this.BringToFront();curControl = sender as Control;if (sender is TextBox){TextBox tb = sender as TextBox;lblDisplay.Text = tb.Text;//设置键盘出现位置Point tbPoint = tb.Location;Point p = new Point();if (tbPoint.Y + this.Height < tb.TopLevelControl.Height || tbPoint.Y < this.Height){p.Y = tbPoint.Y + 2 + tb.Height;}else{p.Y = tbPoint.Y - this.Height - 2;}if (this.Width > tb.TopLevelControl.Width - tbPoint.X){p.X = tbPoint.X + tb.Width - this.Width;}else{p.X = tbPoint.X + 2;}this.Location = p;}}#region 键盘移动Point offsetPoint;bool canMove = false;private void NumKeyBoard_MouseUp(object sender, MouseEventArgs e){canMove = false;}private void NumKeyBoard_MouseDown(object sender, MouseEventArgs e){if (e.Button == MouseButtons.Left){canMove = true;offsetPoint = new Point(-e.X, -e.Y);}}private void NumKeyBoard_MouseMove(object sender, MouseEventArgs e){if (canMove){Point curPoint = this.Parent.PointToClient(Control.MousePosition);curPoint.Offset(offsetPoint);this.Location = curPoint;}}#endregionprivate void NumKeyBoard_Click(object sender, EventArgs e){string key = (sender as Button).Text.Trim().ToLower();lblTitle.Text = "";switch (key){case "-":if (lblDisplay.Text.StartsWith("-")){lblDisplay.Text = lblDisplay.Text.Remove(0, 1);}else{lblDisplay.Text = lblDisplay.Text.Insert(0, "-");}break;case "del":if (lblDisplay.Text.Length > 0){lblDisplay.Text = lblDisplay.Text.Remove(lblDisplay.Text.Length - 1, 1);}break;case "esc":lblDisplay.Text = "";InputCancel?.Invoke(this, null);this.Visible = false;break;case ".":if (lblDisplay.Text.IndexOf('.') != -1){return;}if (string.IsNullOrEmpty(lblDisplay.Text)){lblDisplay.Text = "0.";return;}lblDisplay.Text += ".";break;case "0":if (lblDisplay.Text.Equals("0")){return;}lblDisplay.Text += "0";break;case "enter":try{float value = float.Parse(lblDisplay.Text.Trim());if (value < MinNum || value > MaxNum){lblTitle.Text = $"数值只能位于 {MinNum}~{MaxNum} 之间";System.Media.SystemSounds.Hand.Play();return;}lblDisplay.Text = "";InputCompleted?.Invoke(this, new NumKeyBoardEventArgs(curControl, value));this.Visible = false;}catch (Exception ex){lblTitle.Text = ex.Message;}break;default:if (lblDisplay.Text.Equals("0")){lblDisplay.Text = "";}lblDisplay.Text += key;break;}}float _minNum = 0;[Browsable(true), Category("自定义属性"), Description("最小值")]public float MinNum{get{return _minNum;}set{if (_minNum > MaxNum){_minNum = MaxNum;}else{_minNum = value;}lblMinNum.Text = _minNum.ToString();this.Invalidate();}}float _maxNum = 1000;[Browsable(true), Category("自定义属性"), Description("最小值")]public float MaxNum{get{return _maxNum;}set{if (_maxNum < MinNum){_maxNum = MinNum;}else{_maxNum = value;}lblMaxNum.Text = _maxNum.ToString();this.Invalidate();}}/// <summary>/// 为指定控件添加数字键盘/// </summary>/// <param name="targetControlNames">需要添加数字键盘的控件名集合</param>public void RegisterNumberKeyBoard(string[] targetControlNames){if (targetControlNames != null && targetControlNames.Length != 0){GetControlByControlName(this.TopLevelControl, targetControlNames);}foreach (var item in targetControls){if (item is TextBox){//给该控件注册获取光标事件(item as TextBox).GotFocus += TargetControl_GotFocus;}}}/// <summary>///根据目标控件名获取控件集合/// </summary>/// <param name="control"></param>void GetControlByControlName(Control control, string[] targetNames){if (targetNames.FirstOrDefault(item => item.Equals(control.Name)) != null){targetControls.Add(control);}if (control.HasChildren){foreach (Control c in control.Controls){GetControlByControlName(c, targetNames);}}}}public class NumKeyBoardEventArgs : EventArgs{public NumKeyBoardEventArgs(Control targetControl, float val){this.TargetControl = targetControl;this.Value = val;}/// <summary>/// 目标控件/// </summary>public Control TargetControl { get; private set; }/// <summary>/// 数字键盘输入的值/// </summary>public float Value { get; private set; }}

5,使用Graphics绘制LED。

效果:

LED控件代码:
  public partial class LED : UserControl{public LED(){InitializeComponent();设置控件样式this.SetStyle(ControlStyles.AllPaintingInWmPaint, true);this.SetStyle(ControlStyles.DoubleBuffer, true);this.SetStyle(ControlStyles.ResizeRedraw, true);this.SetStyle(ControlStyles.Selectable, true);this.SetStyle(ControlStyles.SupportsTransparentBackColor, true);this.SetStyle(ControlStyles.UserPaint, true);}float outEllipseWidth = 5;[Browsable(true), Category("自定义属性"), Description("外圆的宽度")]public float OutEllipseWidth{get{return outEllipseWidth;}set{if (value < 0){outEllipseWidth = 2;}else{outEllipseWidth = value;}this.Invalidate();}}Color outEllipseColor = Color.Lime;[Browsable(true), Category("自定义属性"), Description("外圆的颜色")]public Color OutEllipseColor{get{return outEllipseColor;}set{outEllipseColor = value;this.Invalidate();}}float outGapWidth = 3;[Browsable(true), Category("自定义属性"), Description("外间隙宽度")]public float OutCapWidth{get{return outGapWidth;}set{if (value < 0){outGapWidth = 2;}else{outGapWidth = value;}this.Invalidate();}}Color centerEllipseColor = Color.Lime;[Browsable(true), Category("自定义属性"), Description("中心圆的颜色")]public Color CenterEllipseColor{get{return centerEllipseColor;}set{centerEllipseColor = value;this.Invalidate();}}protected override void OnPaint(PaintEventArgs e){base.OnPaint(e);Graphics g = e.Graphics;g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;g.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighQuality;g.TextRenderingHint = System.Drawing.Text.TextRenderingHint.ClearTypeGridFit;//绘制外圆g.DrawEllipse(new Pen(OutEllipseColor, OutEllipseWidth), OutEllipseWidth, OutEllipseWidth, Width - OutEllipseWidth * 2, Height - OutEllipseWidth * 2);//绘制内圆PointF p = new PointF((float)(1.5 * OutEllipseWidth) + OutCapWidth, (float)(1.5 * OutEllipseWidth) + OutCapWidth);float centerWidth = Width - (float)(2 * (1.5 * OutEllipseWidth + OutCapWidth));float centerHeight = Height - (float)(2 * (1.5 * OutEllipseWidth + OutCapWidth));RectangleF centerRec = new RectangleF(p,new SizeF(centerWidth,centerHeight));g.FillEllipse(new SolidBrush(CenterEllipseColor), centerRec);}}

6,使用Graphics绘制流动条。

效果:

F

FlowControl代码 :
 public partial class FlowControl : UserControl{private float startOffset = 0.0f;private Timer mytimer = new Timer();Graphics g;public FlowControl(){InitializeComponent();设置控件样式this.SetStyle(ControlStyles.AllPaintingInWmPaint, true);this.SetStyle(ControlStyles.DoubleBuffer, true);this.SetStyle(ControlStyles.ResizeRedraw, true);this.SetStyle(ControlStyles.Selectable, true);this.SetStyle(ControlStyles.SupportsTransparentBackColor, true);this.SetStyle(ControlStyles.UserPaint, true);mytimer.Interval = 50;mytimer.Tick += Mytimer_Tick;mytimer.Start();}private void Mytimer_Tick(object sender, EventArgs e){startOffset += moveSpeed;if (Math.Abs(startOffset) > BarLength + GapLength){startOffset = 0;}this.Invalidate();}#region Filedsprivate int barHeight = 5;[Browsable(true), Category("自定义属性"), Description("流动条宽度")]public int BarHeight{get { return barHeight; }set{this.barHeight = value;base.Invalidate();}}private Color barColor = Color.DodgerBlue;[Browsable(true), Category("自定义属性"), Description("获取或设置管道控件的流动块颜色")]public Color BarColor{get{return this.barColor;}set{this.barColor = value;base.Invalidate();}}private Color borderColor = Color.DimGray;[Browsable(true), Category("自定义属性"), Description("获取或设置管道边线颜色")]public Color BorderColor{get{return this.borderColor;}set{this.borderColor = value;base.Invalidate();}}private float borderWidth = 1;[Browsable(true), Category("自定义属性"), Description("获取或设置管道壁厚度")]public float BorderWidth{get{return this.borderWidth;}set{this.borderWidth = value;base.Invalidate();}}private Color pipeEdgeColor = Color.DimGray;[Browsable(true), Category("自定义属性"), Description("获取或设置管道边缘颜色")]public Color PipeEdgeColor{get{return this.pipeEdgeColor;}set{this.pipeEdgeColor = value;base.Invalidate();}}private Color pipeCenterColor = Color.LightGray;[Browsable(true), Category("自定义属性"), Description("获取或设置管道控件的中心颜色")]public Color PipeCenterColor{get{return this.pipeCenterColor;}set{this.pipeCenterColor = value;base.Invalidate();}}private PipeTurnDirection pipeTurnLeft = PipeTurnDirection.None;[Browsable(true), Category("自定义属性"), Description("左管道的转向类型")]public PipeTurnDirection PipeTurnLeft{get{return this.pipeTurnLeft;}set{this.pipeTurnLeft = value;base.Invalidate();}}private PipeTurnDirection pipeTurnRight = PipeTurnDirection.None;[Browsable(true), Category("自定义属性"), Description("右管道的转向类型")]public PipeTurnDirection PipeTurnRight{get{return this.pipeTurnRight;}set{this.pipeTurnRight = value;base.Invalidate();}}private DirectionStyle pipeLineDirection = DirectionStyle.Horizontal;[Browsable(true), Category("自定义属性"), Description("设置管道是横向的还是纵向的")]public DirectionStyle PipeLineDirection{get{return this.pipeLineDirection;}set{this.pipeLineDirection = value;int temp;if (value == DirectionStyle.Horizontal){temp = Height;Height = Width;Width = temp;}else{temp = Width;Width = Height;Height = temp;}base.Invalidate();}}private bool isActive = false;[Browsable(true), Category("自定义属性"), DefaultValue(false), Description("获取或设置管道线是否激活液体显示")]public bool IsActive{get{return this.isActive;}set{this.isActive = value;this.mytimer.Enabled = value;base.Invalidate();}}private float moveSpeed = 0.3f;[Browsable(true), Category("自定义属性"), Description("管道线液体流动的速度,0为静止,正数为正向流动,负数为反向流动")]public float MoveSpeed{get{return this.moveSpeed;}set{this.moveSpeed = value;base.Invalidate();}}private int barLength = 5;[Browsable(true), Category("自定义属性"), Description("流动条长度")]public int BarLength{get{return this.barLength;}set{this.barLength = value;base.Invalidate();}}private int gapLength = 5;[Browsable(true), Category("自定义属性"), Description("间隙长度")]public int GapLength{get{return this.gapLength;}set{this.gapLength = value;base.Invalidate();}}#endregionprotected override void OnResize(EventArgs e){if (PipeLineDirection == DirectionStyle.Horizontal){if (Width < 2 * Height){Width = 2 * Height;}}else{if (Height < 2 * Width){Height = 2 * Width;}}base.OnResize(e);}protected override void OnPaint(PaintEventArgs e){//  base.OnPaint(e);g = e.Graphics;Rectangle rec;Rectangle rec2;GraphicsPath graphicsPath = new GraphicsPath();if (PipeLineDirection == DirectionStyle.Horizontal){#region 水平switch (pipeTurnLeft){case PipeTurnDirection.Up:rec = new Rectangle(0, -Height, 2 * Height, 2 * Height);rec2 = new Rectangle(rec.X + (int)BorderWidth / 2, rec.Y, rec.Width - (int)BorderWidth, rec.Height - (int)BorderWidth / 2);PaintElliple(g, rec, rec2, 90, 90);// path.AddArc(new Rectangle( Height / 2, rec.Y /2, Height , Height), 90, 90);//特别需要注意角度旋转方向,如果角度旋转方向选错就形成闭环graphicsPath.AddArc(new Rectangle(this.Height / 2, this.Height / 2 * (-1) - 1, this.Height, this.Height), 180.0f, -90.0f);break;case PipeTurnDirection.Down:rec = new Rectangle(0, 0, 2 * Height, 2 * Height);rec2 = new Rectangle(rec.X + (int)BorderWidth / 2, rec.Y + (int)BorderWidth / 2, rec.Width - (int)BorderWidth, rec.Height - (int)BorderWidth / 2);PaintElliple(g, rec, rec2, 180, 90);graphicsPath.AddArc(new Rectangle(Height / 2, Height / 2, Height, Height), 180, 90);break;case PipeTurnDirection.Left:case PipeTurnDirection.Right:case PipeTurnDirection.None:PointF[] points = new PointF[] { new PointF(Height, BorderWidth / 2), new PointF(0, BorderWidth / 2), new PointF(0, Height - BorderWidth / 2), new PointF(Height, Height - BorderWidth / 2) };PaintRectangle(g, new Rectangle(0, 0, Height, Height), points);graphicsPath.AddLine(new PointF(0, Height / 2), new PointF(Height, Height / 2));break;default:break;}switch (PipeTurnRight){case PipeTurnDirection.Up:rec = new Rectangle(Width - 2 * Height, -Height, 2 * Height, 2 * Height);rec2 = new Rectangle(rec.X + (int)BorderWidth / 2, rec.Y, rec.Width - (int)BorderWidth, rec.Height - (int)BorderWidth / 2);PaintElliple(g, rec, rec2, 0, 90);graphicsPath.AddArc(new Rectangle(rec.X + Height / 2, rec.Y / 2, Height, Height), 90, -90);break;case PipeTurnDirection.Down:rec = new Rectangle(Width - 2 * Height, 0, 2 * Height, 2 * Height);rec2 = new Rectangle(rec.X, rec.Y + (int)BorderWidth / 2, rec.Width - (int)BorderWidth / 2, rec.Height - (int)BorderWidth / 2);PaintElliple(g, rec, rec2, 270, 90);//特别需要注意角度旋转方向,如果角度旋转方向选错就形成闭环graphicsPath.AddArc(new Rectangle(rec.X + Height / 2, Height / 2, Height, Height), 270, 90);break;case PipeTurnDirection.Left:case PipeTurnDirection.Right:case PipeTurnDirection.None:PointF[] points = new PointF[] { new PointF(Width - Height, BorderWidth / 2), new PointF(Width, BorderWidth / 2), new PointF(Width, Height - BorderWidth / 2), new PointF(Width - Height, Height - BorderWidth / 2) };PaintRectangle(g, new Rectangle(Width - Height, 0, Height, Height), points);graphicsPath.AddLine(Width - Height, Height / 2, Width, Height / 2);break;default:break;}if (Width > Height * 2){PointF[] points = new PointF[] { new PointF(Height, BorderWidth / 2), new PointF(Width - Height, BorderWidth / 2), new PointF(Height, Height - BorderWidth / 2), new PointF(Width - Height, Height - BorderWidth / 2) };PaintRectangle(g, new Rectangle(Height, 0, Width - 2 * Height, Height), points);//  graphicsPath.AddLine(Height, Height / 2,Width- Height , Height / 2);}#endregion}else{//垂直switch (pipeTurnLeft){case PipeTurnDirection.Left:rec = new Rectangle(-Width, 0, 2 * Width, 2 * Width);rec2 = new Rectangle(rec.X, rec.Y + (int)BorderWidth / 2, rec.Width - (int)BorderWidth / 2, rec.Height - (int)BorderWidth);PaintElliple(g, rec, rec2, 270, 90);// path.AddArc(new Rectangle( Height / 2, rec.Y /2, Height , Height), 90, 90);//特别需要注意角度旋转方向,如果角度旋转方向选错就形成闭环graphicsPath.AddArc(new Rectangle(-this.Width / 2, this.Width / 2, this.Width, this.Width), 270.0f, 90.0f);break;case PipeTurnDirection.Right:rec = new Rectangle(0, 0, 2 * Width, 2 * Width);rec2 = new Rectangle(rec.X + (int)BorderWidth / 2, rec.Y + (int)BorderWidth / 2, rec.Width - (int)BorderWidth, rec.Height - (int)BorderWidth / 2);PaintElliple(g, rec, rec2, 180, 90);graphicsPath.AddArc(new Rectangle(Width / 2, Width / 2, Width, Width), 270, -90);break;case PipeTurnDirection.Up:case PipeTurnDirection.Down:case PipeTurnDirection.None:PointF[] points = new PointF[] { new PointF(BorderWidth / 2, 0), new PointF(BorderWidth / 2, Width), new PointF(Width - BorderWidth / 2, 0), new PointF(Width - BorderWidth / 2, Width) };PaintRectangle(g, new Rectangle(0, 0, Width, Width), points, LinearGradientMode.Horizontal);graphicsPath.AddLine(new PointF(Width / 2, 0), new PointF(Width / 2, Width));break;default:break;}switch (PipeTurnRight){case PipeTurnDirection.Left:rec = new Rectangle(-Width, Height - 2 * Width, 2 * Width, 2 * Width);rec2 = new Rectangle(rec.X, rec.Y + (int)BorderWidth / 2, rec.Width - (int)BorderWidth / 2, rec.Height - (int)BorderWidth);PaintElliple(g, rec, rec2, 0, 90);//特别需要注意角度旋转方向,如果角度旋转方向选错就形成闭环graphicsPath.AddArc(new Rectangle(rec.X / 2, rec.Y + Width / 2, this.Width, this.Width), 0f, 90.0f);break;case PipeTurnDirection.Right:rec = new Rectangle(0, Height - 2 * Width, 2 * Width, 2 * Width);rec2 = new Rectangle(rec.X + (int)BorderWidth / 2, rec.Y + 1, rec.Width - (int)BorderWidth, rec.Height - (int)BorderWidth / 2);PaintElliple(g, rec, rec2, 90, 90);graphicsPath.AddArc(new Rectangle(Width / 2, rec.Y + Width / 2, Width, Width), 180, -90);break;case PipeTurnDirection.Up:case PipeTurnDirection.Down:case PipeTurnDirection.None:PointF[] points = new PointF[] { new PointF(BorderWidth / 2, Height - Width), new PointF(BorderWidth / 2, Height), new PointF(Width - BorderWidth / 2, Height - Width), new PointF(Width - BorderWidth / 2, Height) };PaintRectangle(g, new Rectangle(0, Height - Width, Width, Width), points, LinearGradientMode.Horizontal);graphicsPath.AddLine(new PointF(Width / 2, Height - Width), new PointF(Width / 2, Height));break;default:break;}if (Height > Width * 2){PointF[] points = new PointF[] { new PointF(BorderWidth / 2, Width), new PointF(BorderWidth / 2, Height - Width), new PointF(Width - BorderWidth / 2, Width), new PointF(Width - BorderWidth / 2, Height - Width) };PaintRectangle(g, new Rectangle(0, Width, Width, Height - 2 * Width), points, LinearGradientMode.Horizontal);// graphicsPath.AddLine(Height, Height / 2,Width- Height , Height / 2);}}if (IsActive){//绘制流动条Pen barPen = new Pen(BarColor, BarHeight);barPen.DashStyle = DashStyle.Custom;barPen.DashOffset = startOffset;barPen.DashPattern = new float[] { BarLength, GapLength };graphicsPath.StartFigure();g.DrawPath(barPen, graphicsPath);}}//绘制椭圆与圆弧void PaintElliple(Graphics g, Rectangle rec, Rectangle recArc, float startAngle, float sweepAngle){GraphicsPath graphicsPath = new GraphicsPath();graphicsPath.AddEllipse(rec);//画刷效果呈现由中心向四方层叠     PathGradientBrush brush = new PathGradientBrush(graphicsPath);brush.CenterPoint = new PointF(rec.X + rec.Width / 2, rec.Y + rec.Height / 2);brush.InterpolationColors = new ColorBlend() { Colors = new Color[] { PipeEdgeColor, PipeCenterColor, PipeEdgeColor }, Positions = new float[] { 0, 0.5f, 1 } };g.FillPie(brush, rec, startAngle, sweepAngle);g.DrawArc(new Pen(BorderColor, BorderWidth), recArc, startAngle, sweepAngle);}void PaintRectangle(Graphics g, Rectangle rec, PointF[] points, LinearGradientMode linearGradientMode = LinearGradientMode.Vertical){//画刷效果呈现线型分布,注意与PathGradientBrush的区别LinearGradientBrush brush = new LinearGradientBrush(rec, PipeEdgeColor, PipeCenterColor, linearGradientMode);brush.InterpolationColors = new ColorBlend() { Colors = new Color[] { PipeEdgeColor, PipeCenterColor, PipeEdgeColor }, Positions = new float[] { 0, 0.5f, 1 } };brush.InterpolationColors = new ColorBlend() { Colors = new Color[] { PipeEdgeColor, PipeCenterColor, PipeEdgeColor }, Positions = new float[] { 0, 0.5f, 1 } };g.FillRectangle(brush, rec);g.DrawLine(new Pen(BorderColor, BorderWidth), points[0], points[1]);g.DrawLine(new Pen(BorderColor, BorderWidth), points[2], points[3]);}}/// <summary>/// 管道左、右的转向类型/// </summary>public enum PipeTurnDirection{Up = 1,Down,Left,Right,None}/// <summary>/// 管道的样式,水平还是数值/// </summary>public enum DirectionStyle{Horizontal = 1,Vertical}

7,使用Graphics绘制仪表盘1:

效果:

DashBoard控件代码
 [DefaultEvent("Click")]//指定默认事件public partial class DashBoard : UserControl{public DashBoard(){InitializeComponent();//  设置控件样式this.SetStyle(ControlStyles.AllPaintingInWmPaint, true);this.SetStyle(ControlStyles.DoubleBuffer, true);this.SetStyle(ControlStyles.ResizeRedraw, true);this.SetStyle(ControlStyles.Selectable, true);this.SetStyle(ControlStyles.SupportsTransparentBackColor, true);this.SetStyle(ControlStyles.UserPaint, true);}Font _wordFont = new Font("微软雅黑", 10, FontStyle.Bold);[Browsable(true), Category("自定义属性"), Description("文字字体")]public Font WordFont{get{return _wordFont;}set{_wordFont = value;this.Invalidate();}}Color _wordColor = Color.Black;/// <summary>/// 文字颜色/// </summary>[Browsable(true), Category("自定义属性"), Description("文字颜色")]public Color WordColor{get{return _wordColor;}set{_wordColor = value;this.Invalidate();}}bool _isWordShow = true;/// <summary>/// 文字是否显示/// </summary>[Browsable(true), Category("自定义属性"), Description("文字是否显示")]public bool IsWordShow{get{return _isWordShow;}set{_isWordShow = value;this.Invalidate();}}string _wordFormat = "实际温度:{0}℃";/// <summary>/// 文字是否显示的格式,例如:"实际温度:{0}℃",{0}为实际值的占位符/// </summary>[Browsable(true), Category("自定义属性"), Description("文字是否显示的格式,例如:'实际温度:{0}℃',{0}为实际值的占位符")]public string WordFormat{get{return _wordFormat;}set{_wordFormat = value;this.Invalidate();}}float _wordPositionFactor = 0.6f;/// <summary>/// 底部文字所在位置/// </summary>[Browsable(true), Category("自定义属性"), Description("底部文字所在位置")]public float WordPositionFactor{get{return _wordPositionFactor;}set{if (value < 0 || value > 1){_wordPositionFactor = 0.6f;}else{_wordPositionFactor = value;}this.Invalidate();}}float _startValue = 0;/// <summary>/// 开始值/// </summary>[Browsable(true), Category("自定义属性"), Description("开始值")]public float StartValue{get{return _startValue;}set{_startValue = value;this.Invalidate();}}float _endValue = 160;/// <summary>/// 结束值/// </summary>[Browsable(true), Category("自定义属性"), Description("结束值")]public float EndValue{get{return _endValue;}set{_endValue = value;this.Invalidate();}}float _sweepRange = 240;/// <summary>/// 量程跨度,即从开始值到结束值所占用的角度/// </summary>[Browsable(true), Category("自定义属性"), Description("量程跨度,即从开始值到结束值所占用的角度")]public float SweepRange{get{return _sweepRange;}set{if (value < 0){_sweepRange = 240;}else{_sweepRange = value;}this.Invalidate();}}int _largeMarkCount = 9;/// <summary>/// 刻度间隔值/// </summary>[Browsable(true), Category("自定义属性"), Description("刻度间隔值")]public int LargeMarkCount{get{return _largeMarkCount;}set{if (value < 0){_largeMarkCount = 9;}else{_largeMarkCount = value;}this.Invalidate();}}MarkType _markStyle = MarkType.Average;/// <summary>/// 刻度分配样式,是平均分配还是自定义刻度值分配/// </summary>[Browsable(true), Category("自定义属性"), Description(" 刻度分配样式,是平均分配还是自定义刻度值分配")]public MarkType MarkStyle{get{return _markStyle;}set{_largeMarkCount = 9;_markStyle = value;this.Invalidate();}}float[] _customMarkValue = { 0, 20, 40, 60, 80, 100, 120, 140, 160 };/// <summary>/// 自定义刻度值/// </summary>[Browsable(true), Category("自定义属性"), Description("自定义刻度值")]public float[] CustomMarkValue{get{return _customMarkValue;}set{_customMarkValue = value;this.Invalidate();}}Color _firstColor = Color.DodgerBlue;/// <summary>/// 第一部分颜色/// </summary>[Browsable(true), Category("自定义属性"), Description("第一部分颜色")]public Color FirstColor{get{return _firstColor;}set{_firstColor = value;this.Invalidate();}}int _firstColorHaveMarkCount = 6;/// <summary>/// 第一部分颜色所拥有的刻度数量/// </summary>[Browsable(true), Category("自定义属性"), Description("第一部分颜色所拥有的刻度数量")]public int FirstColorHaveMarkCount{get{return _firstColorHaveMarkCount;}set{if (value < 0){_firstColorHaveMarkCount = 2;}else{_firstColorHaveMarkCount = value;}this.Invalidate();}}Color _secondColor = Color.LightGray;/// <summary>/// 第2部分颜色/// </summary>[Browsable(true), Category("自定义属性"), Description("第2部分颜色")]public Color SecondColor{get{return _secondColor;}set{_secondColor = value;this.Invalidate();}}int _outCircleWidth = 3;/// <summary>/// 外圆宽度/// </summary>[Browsable(true), Category("自定义属性"), Description("外圆宽度")]public int OutCircleWidth{get{return _outCircleWidth;}set{if (value < 0){return;}else{_outCircleWidth = value;}this.Invalidate();}}float _pointerPartFactor = 0.1f;/// <summary>/// 指针部分所占的比例/// </summary>[Browsable(true), Category("自定义属性"), Description("指针部分所占的比例")]public float PointerPartFactor{get{return _pointerPartFactor;}set{if (value < 0 || value > 1){_pointerPartFactor = 0.2f;}else{_pointerPartFactor = value;}this.Invalidate();}}/// <summary>/// 尺寸/// </summary>int Dimensions{get{if (Width < Height){return Width;}return Height;}}int _outCap = 5;/// <summary>/// 外间隙/// </summary>[Browsable(true), Category("自定义属性"), Description("外间隙")]public int OutGap{get{return _outCap;}set{if (value < 0){return;}_outCap = value;this.Invalidate();}}int _innerCap = 15;/// <summary>/// 内间隙/// </summary>[Browsable(true), Category("自定义属性"), Description("内间隙")]public int InnerGap{get{return _innerCap;}set{if (value < 0){return;}_innerCap = value;this.Invalidate();}}float _actualValue = 60;/// <summary>/// 实际值/// </summary>[Browsable(true), Category("自定义属性"), Description("实际值")]public float ActualValue{get{return _actualValue;}set{_actualValue = value;this.Invalidate();}}Color _markWordColor = Color.Black;[Browsable(true), Category("自定义属性"), Description("刻度文字颜色")]public Color MarkWordColor{get{return _markWordColor;}set{_markWordColor = value;}}Font _markWordFont = DefaultFont;[Browsable(true), Category("自定义属性"), Description("刻度文字字体")]public Font MarkWordFont{get{return _markWordFont;}set{_markWordFont = value;this.Invalidate();}}protected override void OnPaint(PaintEventArgs e){base.OnPaint(e);Graphics g = e.Graphics;//计算需要绘制的刻度数量g.SmoothingMode = SmoothingMode.AntiAlias; //使绘图质量最高,即消除锯齿g.InterpolationMode = InterpolationMode.HighQualityBicubic;g.CompositingQuality = CompositingQuality.HighQuality;Dictionary<int, float> dic = new Dictionary<int, float>();if (MarkStyle == MarkType.Average){for (int i = 0; i < LargeMarkCount; i++){dic.Add(i, i * (SweepRange / (LargeMarkCount - 1)));}}else{for (int i = 0; i < CustomMarkValue.Length; i++){dic.Add(i, (CustomMarkValue[i] - CustomMarkValue.Min()) / Math.Abs((CustomMarkValue.Max() - CustomMarkValue.Min())) * SweepRange);}}//绘制外圆if (FirstColorHaveMarkCount > dic.Count){FirstColorHaveMarkCount = dic.Count;}float startAngle = (360 - SweepRange) / 2 + 90;//第1段g.DrawArc(new Pen(FirstColor, OutCircleWidth), OutGap, OutGap, Dimensions - OutGap * 2, Dimensions - OutGap * 2, startAngle, dic[FirstColorHaveMarkCount - 1]);//第2段g.DrawArc(new Pen(SecondColor, OutCircleWidth), OutGap, OutGap, Dimensions - OutGap * 2, Dimensions - OutGap * 2, dic[FirstColorHaveMarkCount - 1] + startAngle, dic[dic.Count - 1] - dic[FirstColorHaveMarkCount - 1]);//绘制刻度//偏移原点g.TranslateTransform(Dimensions / 2, Dimensions / 2);//旋转角度g.RotateTransform(-_sweepRange / 2);foreach (var key in dic.Keys){RectangleF rec = new RectangleF(-2, -(Dimensions - 2 * OutGap) / 2 - OutGap, 4, OutGap * 2);if (key != 0){g.RotateTransform(dic[key] - dic[key - 1]);}if (key < FirstColorHaveMarkCount){g.FillRectangle(new SolidBrush(FirstColor), rec);}else{g.FillRectangle(new SolidBrush(SecondColor), rec);}}//恢复坐标g.ResetTransform();//移动原点g.TranslateTransform(Dimensions / 2, Dimensions / 2);//旋转角度//  g.RotateTransform(-_sweepRange / 2);//绘制MarkWord//  PointF p = new PointF((float)(Dimensions * Math.Cos(230*1.0 / 180 * Math.PI)), (float)(Dimensions * Math.Sin(230*1.0 / 180 * Math.PI)));// g.DrawLine(Pens.Black, new PointF(0, 0), p);float largeInterval = SweepRange / (LargeMarkCount - 1);foreach (var key in dic.Keys){//绘制文字string markWord;if (MarkStyle == MarkType.Average){markWord = Math.Round(StartValue + key * (EndValue - StartValue) / (LargeMarkCount - 1), 1).ToString();}else{markWord = Math.Round(CustomMarkValue[key], 1).ToString();}float wordRadius = Dimensions / 2 - OutCircleWidth - OutGap - InnerGap;double x = wordRadius * Math.Cos((dic[key] + startAngle) / 180 * Math.PI);double y = wordRadius * Math.Sin((dic[key] + startAngle) / 180 * Math.PI);SizeF size = g.MeasureString(markWord, this.Font);PointF wordPoint = new PointF((float)x - size.Width / 2, (float)y - size.Height / 2);g.DrawString(markWord, MarkWordFont, new SolidBrush(MarkWordColor), wordPoint);}if (IsWordShow){//绘制底部文字string txt = string.Format(WordFormat, ActualValue);SizeF wordSize = g.MeasureString(txt, WordFont);PointF txtPoint = new PointF(-wordSize.Width / 2, Dimensions / 2 * WordPositionFactor);g.DrawString(txt, WordFont, new SolidBrush(WordColor), txtPoint);}//绘制指针//圆心半径float circleRadius = Dimensions / 2 * this.PointerPartFactor;float pointerLength = circleRadius * 6;float trackWidth = pointerLength / 4;//绘制指针圆心g.FillEllipse(new SolidBrush(FirstColor), -circleRadius, -circleRadius, 2 * circleRadius, 2 * circleRadius);float relativeAngle;if (ActualValue > EndValue){relativeAngle = SweepRange;}else if (ActualValue < StartValue){relativeAngle = 0;}else{if (MarkStyle == MarkType.Average){relativeAngle = ((ActualValue - StartValue) / (EndValue - StartValue)) * SweepRange;}else{if (CustomMarkValue.Length < 2){CustomMarkValue = new float[] { 0, 20, 30 };}relativeAngle = (ActualValue - CustomMarkValue.Min()) / (CustomMarkValue.Max() - CustomMarkValue.Min()) * SweepRange;}}//绘制轨迹g.DrawArc(new Pen(FirstColor, trackWidth), -pointerLength + trackWidth / 2, -pointerLength + trackWidth / 2, 2 * pointerLength - trackWidth, 2 * pointerLength - trackWidth, startAngle, relativeAngle);//旋转角度g.RotateTransform(-_sweepRange / 2);//当前值对应的相对角度//绘制指针g.RotateTransform(relativeAngle);g.DrawLine(new Pen(FirstColor, 2), -1, 0, -1, -pointerLength);}}public enum MarkType{/// <summary>/// 平均分配刻度/// </summary>Average,/// <summary>/// 自定义刻度值分配/// </summary>Custom}
}

8,使用Graphics绘制仪表盘2:

效果:

Gague控件代码:
 [DefaultEvent("Click")]public partial class Gague : UserControl{public Gague(){InitializeComponent();//  设置控件样式this.SetStyle(ControlStyles.AllPaintingInWmPaint, true);this.SetStyle(ControlStyles.DoubleBuffer, true);this.SetStyle(ControlStyles.ResizeRedraw, true);this.SetStyle(ControlStyles.Selectable, true);this.SetStyle(ControlStyles.SupportsTransparentBackColor, true);this.SetStyle(ControlStyles.UserPaint, true);}Font _wordFont = new Font("微软雅黑", 10, FontStyle.Bold);[Browsable(true), Category("自定义属性"), Description("文字字体")]public Font WordFont{get{return _wordFont;}set{_wordFont = value;this.Invalidate();}}Color _wordColor = Color.SeaGreen;/// <summary>/// 文字颜色/// </summary>[Browsable(true), Category("自定义属性"), Description("文字颜色")]public Color WordColor{get{return _wordColor;}set{_wordColor = value;this.Invalidate();}}bool _isWordShow = true;/// <summary>/// 文字是否显示/// </summary>[Browsable(true), Category("自定义属性"), Description("文字是否显示")]public bool IsWordShow{get{return _isWordShow;}set{_isWordShow = value;this.Invalidate();}}string _wordFormat = "实际温度:{0}℃";/// <summary>/// 文字是否显示的格式,例如:"实际温度:{0}℃",{0}为实际值的占位符/// </summary>[Browsable(true), Category("自定义属性"), Description("文字是否显示的格式,例如:'实际温度:{0}℃',{0}为实际值的占位符")]public string WordFormat{get{return _wordFormat;}set{_wordFormat = value;this.Invalidate();}}float _wordPositionFactor = 0.7f;/// <summary>/// 底部文字所在位置/// </summary>[Browsable(true), Category("自定义属性"), Description("底部文字所在位置")]public float WordPositionFactor{get{return _wordPositionFactor;}set{if (value < 0 || value > 1){_wordPositionFactor = 0.6f;}else{_wordPositionFactor = value;}this.Invalidate();}}float _startValue = 0;/// <summary>/// 开始值/// </summary>[Browsable(true), Category("自定义属性"), Description("开始值")]public float StartValue{get{return _startValue;}set{_startValue = value;this.Invalidate();}}float _endValue = 160;/// <summary>/// 结束值/// </summary>[Browsable(true), Category("自定义属性"), Description("结束值")]public float EndValue{get{return _endValue;}set{_endValue = value;this.Invalidate();}}float _lowAlarmValue = 25;/// <summary>/// 低报警阈值/// </summary>[Browsable(true), Category("自定义属性"), Description("低警戒值")]public float LowAlarmValue{get{return _lowAlarmValue;}set{if (value < StartValue){_lowAlarmValue = StartValue;}else{_lowAlarmValue = value;}this.Invalidate();}}Color _lowAlarmColor = Color.Red;/// <summary>/// 低警区域颜色/// </summary>[Browsable(true), Category("自定义属性"), Description("低警区域颜色")]public Color LowAlarmColor{get{return _lowAlarmColor;}set{_lowAlarmColor = value;this.Invalidate();}}float _hightAlarmValue = 120;/// <summary>/// 高报警阈值/// </summary>[Browsable(true), Category("自定义属性"), Description("高警戒值")]public float HightAlarmValue{get{return _hightAlarmValue;}set{if (value > EndValue){_hightAlarmValue = EndValue;}else{_hightAlarmValue = value;}this.Invalidate();}}Color _hightAlarmColor = Color.Red;/// <summary>/// 高报警区域颜色/// </summary>[Browsable(true), Category("自定义属性"), Description("高警区域颜色")]public Color HightAlarmColor{get{return _hightAlarmColor;}set{_hightAlarmColor = value;this.Invalidate();}}float _sweepRange = 240;/// <summary>/// 量程跨度,即从开始值到结束值所占用的角度/// </summary>[Browsable(true), Category("自定义属性"), Description("量程跨度,即从开始值到结束值所占用的角度")]public float SweepRange{get{return _sweepRange;}set{if (value < 0){_sweepRange = 240;}else{_sweepRange = value;}this.Invalidate();}}Color _markColor = Color.LightSeaGreen;/// <summary>/// 刻度颜色/// </summary>[Browsable(true), Category("自定义属性"), Description("刻度颜色")]public Color MarkColor{get{return _markColor;}set{_markColor = value;this.Invalidate();}}Color _pointerColor = Color.Green;/// <summary>/// 指针颜色/// </summary>[Browsable(true), Category("自定义属性"), Description("指针颜色")]public Color PointerColor{get{return _pointerColor;}set{_pointerColor = value;this.Invalidate();}}float _pointerPartFactor = 0.8f;/// <summary>/// 指针部分所占的比例/// </summary>[Browsable(true), Category("自定义属性"), Description("指针部分所占的比例")]public float PointerPartFactor{get{return _pointerPartFactor;}set{if (value < 0 || value > 1){_pointerPartFactor = 0.2f;}else{_pointerPartFactor = value;}this.Invalidate();}}/// <summary>/// 尺寸/// </summary>int Dimensions{get{if (Width < Height){return Width;}return Height;}}int _outCap = 5;/// <summary>/// 外间隙/// </summary>[Browsable(true), Category("自定义属性"), Description("外间隙")]public int OutGap{get{return _outCap;}set{if (value < 0){return;}_outCap = value;this.Invalidate();}}int _innerCap = 3;/// <summary>/// 内间隙/// </summary>[Browsable(true), Category("自定义属性"), Description("内间隙")]public int InnerGap{get{return _innerCap;}set{if (value < 0){return;}_innerCap = value;this.Invalidate();}}float _actualValue = 60;/// <summary>/// 实际值/// </summary>[Browsable(true), Category("自定义属性"), Description("实际值")]public float ActualValue{get{return _actualValue;}set{_actualValue = value;this.Invalidate();}}Color _markWordColor = Color.Black;[Browsable(true), Category("自定义属性"), Description("刻度文字颜色")]public Color MarkWordColor{get{return _markWordColor;}set{_markWordColor = value;}}Font _markWordFont = DefaultFont;[Browsable(true), Category("自定义属性"), Description("刻度文字颜色")]public Font MarkWordFont{get{return _markWordFont;}set{_markWordFont = value;this.Invalidate();}}int _largeMarkCount = 9;[Browsable(true), Category("自定义属性"), Description("大刻度数量")]public int LargeMarkCount{get{return _largeMarkCount;}set{if (value < 0){_largeMarkCount = 5;}else{_largeMarkCount = value;}this.Invalidate();}}int _markWidth = 3;[Browsable(true), Category("自定义属性"), Description("刻度宽度")]public int MarkWidth{get{return _markWidth;}set{if (value < 0){_markWidth = 3;}else{_markWidth = value;}this.Invalidate();}}int _markHeight = 4;[Browsable(true), Category("自定义属性"), Description("刻度宽度")]public int MarkHeight{get{return _markHeight;}set{if (value < 0){_markHeight = 4;}else{_markHeight = value;}this.Invalidate();}}int _markWordGap = 24;[Browsable(true), Category("自定义属性"), Description("刻度文字与刻度间隙")]public int MarkWordGap{get{return _markWordGap;}set{if (value < 0){_markWordGap = 4;}else{_markWordGap = value;}this.Invalidate();}}protected override void OnPaint(PaintEventArgs e){base.OnPaint(e);Graphics g = e.Graphics;g.SmoothingMode = SmoothingMode.AntiAlias; //使绘图质量最高,即消除锯齿g.InterpolationMode = InterpolationMode.HighQualityBicubic;g.CompositingQuality = CompositingQuality.HighQuality;g.SmoothingMode = SmoothingMode.HighQuality;//绘制刻度//计算小刻度大小float smallMarkAngle = SweepRange / ((LargeMarkCount - 1) * 5);g.TranslateTransform(Dimensions / 2, Dimensions / 2);float offset = OutGap + InnerGap + MarkHeight;g.RotateTransform(-_sweepRange / 2);for (int i = 0; i <= LargeMarkCount - 1; i++){//绘制大刻度PointF[] points = new PointF[]{new PointF(-MarkWidth*1.0f/2, offset-Dimensions/2),new PointF(MarkWidth*1.0f/2,offset-Dimensions/2),new PointF(MarkWidth*1.0f/2,offset+MarkHeight*2-Dimensions/2),new PointF(0,offset+MarkHeight*2+  MarkWidth*1.0f/2-Dimensions/2),new PointF(-MarkWidth*1.0f/2,offset+MarkHeight*2-Dimensions/2)};g.FillPolygon(new SolidBrush(MarkColor), points);g.RotateTransform(smallMarkAngle);if (i != LargeMarkCount - 1){//绘制小刻度for (int j = 0; j < 4; j++){g.FillRectangle(new SolidBrush(MarkColor), -MarkWidth * 1.0f / 2, offset - Dimensions / 2, MarkWidth, MarkHeight);g.RotateTransform(smallMarkAngle);}}}//初始化原点,并将原点置于圆心g.ResetTransform();g.TranslateTransform(Dimensions / 2, Dimensions / 2);float startAngle = 180 - SweepRange / 2 + 90;float lowAlarmAngle;if (LowAlarmValue == StartValue){lowAlarmAngle = 0;}else{lowAlarmAngle = (LowAlarmValue - StartValue) * 1.0f / (EndValue - StartValue) * SweepRange;}float hightAlarmAngle;if (HightAlarmValue == EndValue){hightAlarmAngle = 0;}else{hightAlarmAngle = (EndValue - HightAlarmValue) * 1.0f / (EndValue - StartValue) * SweepRange;}//绘制警戒线Pen lowAlarmPen = new Pen(LowAlarmColor, MarkWidth){DashStyle = DashStyle.Dash,DashPattern = new float[] { 3, 1 }};Pen hightAlarmPen = new Pen(HightAlarmColor, MarkWidth){DashStyle = DashStyle.Dash,DashPattern = new float[] { 3, 1 }};g.DrawArc(lowAlarmPen, OutGap - Dimensions / 2, OutGap - Dimensions / 2, Dimensions - 2 * OutGap, Dimensions - 2 * OutGap, startAngle, lowAlarmAngle);g.DrawArc(hightAlarmPen, OutGap - Dimensions / 2, OutGap - Dimensions / 2, Dimensions - 2 * OutGap, Dimensions - 2 * OutGap, startAngle + SweepRange - hightAlarmAngle, hightAlarmAngle);//绘制刻度文字float largeMarkInterval = (EndValue - StartValue) / (LargeMarkCount - 1);for (int i = 0; i <= LargeMarkCount - 1; i++){float angle = startAngle + i * 5 * smallMarkAngle;float radius = Dimensions / 2 - (OutGap + MarkWidth + InnerGap + MarkWordGap);PointF p = new PointF(radius * (float)(Math.Cos(angle / 180 * Math.PI)), radius * (float)(Math.Sin(angle / 180 * Math.PI)));string wordtxt = (Math.Round(StartValue + i * largeMarkInterval, 1)).ToString();SizeF wordSize = g.MeasureString(wordtxt, MarkWordFont);PointF wordPoint = new PointF(p.X - wordSize.Width / 2, p.Y - wordSize.Height / 2);g.DrawString(wordtxt, MarkWordFont, new SolidBrush(MarkWordColor), wordPoint);//  g.DrawLine(Pens.Black, new Point(0, 0), p);}//绘制文字if (this.IsWordShow){string word = string.Format(WordFormat, ActualValue);SizeF wSize = g.MeasureString(word, WordFont);float wordPosition = Dimensions / 2 * this.WordPositionFactor;PointF wPoint = new PointF(-wSize.Width / 2, wordPosition - wSize.Height / 2);g.DrawString(word, WordFont, new SolidBrush(WordColor), wPoint);}//绘制指针//使指针置于0位g.RotateTransform(-SweepRange / 2);//计算旋转的角度if (StartValue != EndValue){float pointerAngle;if (ActualValue < StartValue){pointerAngle = 0;}else if (ActualValue > EndValue){pointerAngle = SweepRange;}else{pointerAngle = (ActualValue - StartValue) / (EndValue - StartValue) * SweepRange;}g.RotateTransform(pointerAngle);}float pointerLenght = Dimensions / 2 * PointerPartFactor;float centerRadius = pointerLenght / 30;GraphicsPath path = new GraphicsPath();path.AddArc(-centerRadius, -centerRadius, 2 * centerRadius, 2 * centerRadius, 0, 180);path.AddLine(-centerRadius, 0, 0, -pointerLenght);g.FillPath(new SolidBrush(PointerColor), path);}}

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • JavaScript - Api学习 Day03 (日期对象、节点操作、两种定时器、本地存储)
  • moonlight串流配置太复杂?推荐一款无需配置的宝藏串流软件GameViewer远程
  • DevOps学习笔记
  • CSS学习8[重点]--盒子模型边框、内外边距设定和外边距合并
  • 九九乘法口决表
  • idea中git提交或push到远程后回退到之前的某次提交简单有效的解决方案
  • HarmonyOS开发实战( Beta5.0)DevEco Device Tool开发环境搭建实践
  • AI人的年度盛典:星河产业应用创新奖启动申报
  • 安全入门day.04
  • 数学建模--皮尔逊相关系数、斯皮尔曼相关系数
  • 给自己复盘用的随想录笔记-栈与队列
  • 【2024高教社杯全国大学生数学建模竞赛】B题 生产过程中的决策问题——解题思路 代码 论文
  • 华为OD机试真题-猜数字-2024年OD统一考试(E卷)
  • 基于 AC 驱动的电容结构 GaN LED 模型开发和应用
  • k8s helm
  • [PHP内核探索]PHP中的哈希表
  • 「前端」从UglifyJSPlugin强制开启css压缩探究webpack插件运行机制
  • Android开源项目规范总结
  • input实现文字超出省略号功能
  • java 多线程基础, 我觉得还是有必要看看的
  • PAT A1092
  • Vue UI框架库开发介绍
  • Vue2.0 实现互斥
  • 初识 beanstalkd
  • 从@property说起(二)当我们写下@property (nonatomic, weak) id obj时,我们究竟写了什么...
  • 对JS继承的一点思考
  • 每个JavaScript开发人员应阅读的书【1】 - JavaScript: The Good Parts
  • 微信小程序设置上一页数据
  • 限制Java线程池运行线程以及等待线程数量的策略
  • 与 ConTeXt MkIV 官方文档的接驳
  • Mac 上flink的安装与启动
  • mysql面试题分组并合并列
  • puppet连载22:define用法
  • UI设计初学者应该如何入门?
  • ​ArcGIS Pro 如何批量删除字段
  • #《AI中文版》V3 第 1 章 概述
  • $LayoutParams cannot be cast to android.widget.RelativeLayout$LayoutParams
  • (4)通过调用hadoop的java api实现本地文件上传到hadoop文件系统上
  • (LNMP) How To Install Linux, nginx, MySQL, PHP
  • (MIT博士)林达华老师-概率模型与计算机视觉”
  • (MTK)java文件添加简单接口并配置相应的SELinux avc 权限笔记2
  • (PHP)设置修改 Apache 文件根目录 (Document Root)(转帖)
  • (附源码)springboot家庭装修管理系统 毕业设计 613205
  • (蓝桥杯每日一题)love
  • (企业 / 公司项目)前端使用pingyin-pro将汉字转成拼音
  • (转载)微软数据挖掘算法:Microsoft 时序算法(5)
  • .gitignore
  • .Mobi域名介绍
  • .NET Core 发展历程和版本迭代
  • .Net 代码性能 - (1)
  • .NET 使用 JustAssembly 比较两个不同版本程序集的 API 变化
  • .NET正则基础之——正则委托
  • :O)修改linux硬件时间
  • :如何用SQL脚本保存存储过程返回的结果集
  • @Autowired多个相同类型bean装配问题