前言
- 本文描述了如何使用Winform窗体中的控件,绘制形状(如:矩形),实现添加、删除、选中、移动、缩放。点击按钮添加矩形。
- WinForms (Windows Forms) 是微软.NET框架中的一个图形用户界面(GUI)类库,用于开发Windows桌面应用程序。
- 在创建窗体后可以通过拖拽方式创建各种控件(如文本框按钮等)。

演示案例
运行效果1

运行效果2

代码讲解
Shape类

public abstract class Shape
{
#region 字段、属性
private int _id = -1;
private Color _shapeColor = Color.Blue; //填充颜色
private Color _handleColor = Color.Blue; //边框颜色
private float _borderWidth = 0; //边缘宽度
private int _alpha = 50; // 透明度
private int _handleSize = 8; // 手柄的视觉大小
private int _handleOutSize = 16; // 手柄外区域大小(比视觉大)
private bool _isSelected = true; //选中状态
private static int _nextId = 0;
public int ID { get => _id; private set => _id = value; }
public Color ShapeColor { get => _shapeColor; set => _shapeColor = value; }
public Color HandleColor { get => _handleColor; set => _handleColor = value; }
public float BorderWidth { get => _borderWidth; set => _borderWidth = value; }
public int Alpha { get => _alpha; set => _alpha = value; }
public int HandleSize
{
get => _handleSize;
set
{
if (_handleSize != value)
{
_handleSize = value;
HandleOutSize = value * 2;
}
}
}
public int HandleOutSize {
get => _handleOutSize;
set
{
if (_handleOutSize != value)
{
_handleOutSize = value;
_handleSize = value / 2;
}
}
}
public bool IsSelected { get => _isSelected; set => _isSelected = value; }
#endregion
#region 构造函数
protected Shape()
{
//获取不重复的ID,当前程序运行生效。
ID = Interlocked.Increment(ref _nextId);
}
#endregion
#region 抽象方法
/// <summary>
/// 点是否在手柄上
/// </summary>
public abstract bool IsInHandle(Point point, int x, int y);
/// <summary>
/// 获取手柄类型
/// </summary>
public abstract HandleType GetHandleType(Point point);
/// <summary>
/// 绘制手柄
/// </summary>
protected abstract void DrawHandle(Graphics graphics, int x, int y);
/// <summary>
/// 绘制形状和手柄
/// </summary>
public abstract void DrawShapeWithHandles(Graphics graphics);
#endregion
}
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
- 20.
- 21.
- 22.
- 23.
- 24.
- 25.
- 26.
- 27.
- 28.
- 29.
- 30.
- 31.
- 32.
- 33.
- 34.
- 35.
- 36.
- 37.
- 38.
- 39.
- 40.
- 41.
- 42.
- 43.
- 44.
- 45.
- 46.
- 47.
- 48.
- 49.
- 50.
- 51.
- 52.
- 53.
- 54.
- 55.
- 56.
- 57.
- 58.
- 59.
- 60.
- 61.
- 62.
- 63.
- 64.
- 65.
- 66.
- 67.
- 68.
URectangle 类
- 继承Shape类,方便统一形状。
创建矩形的基本属性:
- 矩形的基本属性参数(X,Y,Width,Height)。
- Rectangle 实际显示的矩形,RectangleF :用于缩放转换矩形
重写方法:
- 重写形状方法,实现具体的绘制图形功能。
public class URectangle: Shape
{
#region 字段|属性
private Rectangle rectangle;
public Rectangle Rectangle
{
get => rectangle;
set => rectangle = value;
}
private RectangleF rectangleF;
public RectangleF RectangleF
{
get => rectangleF;
set => rectangleF = value;
}
public int X {
get { return rectangle.X; }
set
{
if (rectangle != null) rectangle.X = value;
}
}
public int Y {
get { return rectangle.Y; }
set
{
if (rectangle != null) rectangle.Y = value;
}
}
public Point Point
{
get => new Point(X, Y);
set
{
X = value.X;
Y = value.Y;
}
}
public int Width {
get => rectangle.Width;
set
{
if (rectangle!=null)
{
rectangle.Width = value;
}
}
}
public int Height {
get => rectangle.Height;
set
{
if (rectangle != null)
{
rectangle.Height = value;
}
}
}
public Size Location
{
get => new Size(Width, Width);
set
{
Width = value.Width;
Width = value.Width;
}
}
#endregion
#region 构造函数
public URectangle():base()
{
}
public URectangle(Rectangle rectangle)
{
this.rectangle = rectangle;
}
#endregion
#region 绘制矩形相关
/// <summary>
/// 绘制矩形和手柄(选中时绘制):
/// </summary>
public override void DrawShapeWithHandles(Graphics graphics)
{
using (var brush = new SolidBrush(Color.FromArgb(Alpha, ShapeColor)))
{
graphics.FillRectangle(brush, rectangle);
}
Pen pen = new Pen(ShapeColor, BorderWidth);
graphics.DrawRectangle(pen, rectangle);
if (IsSelected)
{
DrawHandle(graphics, rectangle.Left, rectangle.Top); // 左上角
DrawHandle(graphics, rectangle.Right, rectangle.Top); // 右上角
DrawHandle(graphics, rectangle.Left, rectangle.Bottom); // 左下角
DrawHandle(graphics, rectangle.Right, rectangle.Bottom); // 右下角
}
}
/// <summary>
/// 绘制手柄:
/// </summary>
protected override void DrawHandle(Graphics graphics, int x, int y)
{
Rectangle handleRect = new Rectangle( x - HandleSize / 2,y - HandleSize / 2,HandleSize,HandleSize);
using (var brush = new SolidBrush(Color.FromArgb(Alpha, HandleColor)))
{
graphics.FillRectangle(brush, handleRect);
}
Pen pen = new Pen(HandleColor, BorderWidth);
graphics.DrawRectangle(pen, handleRect);
}
/// <summary>
/// 获取要显示的手柄类型:根据指定点,判断当前矩形应该使用什么类型的手柄。
/// </summary>
public override HandleType GetHandleType(Point point)
{
if (IsInHandle(point, rectangle.Left, rectangle.Top))
return HandleType.TopLeft;
if (IsInHandle(point, rectangle.Right, rectangle.Top))
return HandleType.TopRight;
if (IsInHandle(point, rectangle.Left, rectangle.Bottom))
return HandleType.BottomLeft;
if (IsInHandle(point, rectangle.Right, rectangle.Bottom))
return HandleType.BottomRight;
return HandleType.None;
}
/// <summary>
/// 指定点是否在手柄范围内
/// </summary>
public override bool IsInHandle(Point point, int x, int y)
{
Rectangle handleRect = new Rectangle(x - HandleOutSize / 2,y - HandleOutSize / 2,HandleOutSize,HandleOutSize);
return handleRect.Contains(point);
}
#endregion
}
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
- 20.
- 21.
- 22.
- 23.
- 24.
- 25.
- 26.
- 27.
- 28.
- 29.
- 30.
- 31.
- 32.
- 33.
- 34.
- 35.
- 36.
- 37.
- 38.
- 39.
- 40.
- 41.
- 42.
- 43.
- 44.
- 45.
- 46.
- 47.
- 48.
- 49.
- 50.
- 51.
- 52.
- 53.
- 54.
- 55.
- 56.
- 57.
- 58.
- 59.
- 60.
- 61.
- 62.
- 63.
- 64.
- 65.
- 66.
- 67.
- 68.
- 69.
- 70.
- 71.
- 72.
- 73.
- 74.
- 75.
- 76.
- 77.
- 78.
- 79.
- 80.
- 81.
- 82.
- 83.
- 84.
- 85.
- 86.
- 87.
- 88.
- 89.
- 90.
- 91.
- 92.
- 93.
- 94.
- 95.
- 96.
- 97.
- 98.
- 99.
- 100.
- 101.
- 102.
- 103.
- 104.
- 105.
- 106.
- 107.
- 108.
- 109.
- 110.
- 111.
- 112.
- 113.
- 114.
- 115.
- 116.
- 117.
- 118.
- 119.
- 120.
- 121.
- 122.
- 123.
- 124.
- 125.
- 126.
- 127.
- 128.
- 129.
- 130.
- 131.
- 132.
- 133.
- 134.
- 135.
ShapeModule 类 -
- 创建URectangle 类对象只能创建基本的形状,具体还需要将形状图形绘制到控件中,下面的模块就是如何实现该绘制形状到控件容器中。
通过创建事件、并给容器绑定事件,然后根据事件操作判断实现功能:

public class ShapeModule
{
#region 字段 | 属性
private float scaleX = 1.0f; //缩放X
private float scaleY = 1.0f; //缩放Y
private bool isScaled = false; //是否缩放
private int selectedIndex = -1; //选择索引
private DrawMode currentMode = DrawMode.None; //当前模式
private HandleType handleType = HandleType.None; //手柄类型
private Point startPoint; //起始点
private Control container; //形状显示容器
private URectangle currentRect; //当前矩形
private URectangle displayRect; //选择的矩形
private ContextMenuStrip rightKeyMenuStrip; //右键菜单
private Dictionary<int, Shape> _shapeDictionary; //形状存储字典
public float ScaleX
{
get => scaleX;
set
{
scaleX = value;
UpdateDisplayShape();
}
}
public float ScaleY
{
get => scaleY;
set
{
scaleY = value;
UpdateDisplayShape();
}
}
public DrawMode CurrentMode
{
get => currentMode;
set => currentMode = value;
}
public Dictionary<int, Shape> ShapeDictionary { get => _shapeDictionary;private set => _shapeDictionary = value; }
#endregion
#region 构造函数
public ShapeModule(Control container)
{
Initialize(container);
}
#endregion
#region 初始化
private void Initialize(Control container)
{
this.container = container;
ShapeDictionary = new Dictionary<int, Shape>();
InitializeContainer();
InitializeRightKeyMenu();
}
#region 初始化容器
private void InitializeContainer()
{
container.MouseDown += Container_MouseDown;
container.MouseUp += Container_MouseUp;
container.MouseMove += Container_MouseMove;
container.MouseUp += Container_MouseUp;
container.MouseWheel += Container_MouseWheel;
container.Paint += Container_Paint;
}
#endregion
#region 右键菜单功能
private void InitializeRightKeyMenu()
{
// 创建菜单项
rightKeyMenuStrip = new ContextMenuStrip();
var copyItem = new ToolStripMenuItem("复制");
copyItem.Click += (s, e) => CopyAction();
var deleteItem = new ToolStripMenuItem("删除");
deleteItem.Click += (s, e) => DeleteAction();
// 创建右键菜单
rightKeyMenuStrip.Items.Add(copyItem);
rightKeyMenuStrip.Items.Add(deleteItem);
}
private void CopyAction()
{
}
private void DeleteAction()
{
ShapeDictionary.Remove(selectedIndex);
selectedIndex = -1;
container.Invalidate();
}
#endregion
#endregion
#region 形状显示相关:缩放、显示
/// <summary>
/// 更新显示形状
/// </summary>
private void UpdateDisplayShape()
{
foreach (var shape in ShapeDictionary.Values)
{
if (shape is URectangle rectangle)
{
rectangle.Rectangle = new Rectangle(
(int)(rectangle.RectangleF.X * scaleX),
(int)(rectangle.RectangleF.Y * scaleY),
(int)(rectangle.RectangleF.Width * scaleX),
(int)(rectangle.RectangleF.Height * scaleY));
}
}
container.Invalidate();
}
/// <summary>
/// 缩小
/// </summary>
private RectangleF ScaleDown(Rectangle rect)
{
return new RectangleF(
rect.X / scaleX,
rect.Y / scaleY,
rect.Width / scaleX,
rect.Height / scaleY);
}
/// <summary>
/// 放大
/// </summary>
private Rectangle ScaleUp(RectangleF rect)
{
return new Rectangle(
(int)(rect.X * scaleX),
(int)(rect.Y * scaleY),
(int)(rect.Width * scaleX),
(int)(rect.Height * scaleY));
}
/// <summary>
/// 放大
/// </summary>
private void ZoomIn()
{
ScaleX += 0.1F;
ScaleY += 0.1F;
}
/// <summary>
/// 缩小
/// </summary>
private void ZoomOut()
{
ScaleX -= 0.1F;
ScaleY -= 0.1F;
}
#endregion
#region 事件
private void Container_MouseDown(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
// 形状绘制
if (CurrentMode == DrawMode.Drawing)
{
currentRect = new URectangle();
startPoint = e.Location;
currentRect.Rectangle = new Rectangle(e.Location, Size.Empty);
}
// 形状移动
else if (CurrentMode == DrawMode.Moving)
{
int dx = e.X - startPoint.X;
int dy = e.Y - startPoint.Y;
displayRect.X += dx;
displayRect.Y += dy;
displayRect.RectangleF = ScaleDown(displayRect.Rectangle);
startPoint = e.Location;
}
// 形状调整大小
else if (CurrentMode == DrawMode.Resizing)
{
Rectangle rect = displayRect.Rectangle;
switch (handleType)
{
case HandleType.TopLeft:
rect.X = e.X;
rect.Y = e.Y;
rect.Width = displayRect.Rectangle.Right - e.X;
rect.Height = displayRect.Rectangle.Bottom - e.Y;
break;
case HandleType.TopRight:
rect.Y = e.Y;
rect.Width = e.X - displayRect.Rectangle.Left;
rect.Height = displayRect.Rectangle.Bottom - e.Y;
break;
case HandleType.BottomLeft:
rect.X = e.X;
rect.Width = displayRect.Rectangle.Right - e.X;
rect.Height = e.Y - displayRect.Rectangle.Top;
break;
case HandleType.BottomRight:
rect.Width = e.X - displayRect.Rectangle.Left;
rect.Height = e.Y - displayRect.Rectangle.Top;
break;
}
// 确保宽度和高度不为负
if (rect.Width > 0 && rect.Height > 0)
{
displayRect.RectangleF = ScaleDown(rect);
displayRect.Rectangle = rect;
}
}
// 形状判断选择
else
{
selectedIndex = -1;
foreach (var shape in ShapeDictionary.Values)
{
if (shape is URectangle uRectangle)
{
if (uRectangle.Rectangle.Contains(e.Location)
|| uRectangle.GetHandleType(e.Location) != HandleType.None)
{
selectedIndex = uRectangle.ID;
displayRect = uRectangle;
startPoint = e.Location;
handleType = uRectangle.GetHandleType(e.Location);
CurrentMode = handleType != HandleType.None ? DrawMode.Resizing : DrawMode.Moving;
break;
}
}
}
}
}
//右键菜单
if (e.Button == MouseButtons.Right)
{
if (selectedIndex != -1)
{
rightKeyMenuStrip.Show(container, e.Location);
}
}
container.Invalidate();
}
private void Container_MouseMove(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
if (CurrentMode == DrawMode.Drawing)
{
int x = Math.Min(startPoint.X, e.X);
int y = Math.Min(startPoint.Y, e.Y);
int width = Math.Abs(startPoint.X - e.X);
int height = Math.Abs(startPoint.Y - e.Y);
currentRect.Rectangle = new Rectangle(x, y, width, height);
}
else if (CurrentMode == DrawMode.Moving && selectedIndex >= 0)
{
int dx = e.X - startPoint.X;
int dy = e.Y - startPoint.Y;
displayRect.X += dx;
displayRect.Y += dy;
ShapeDictionary[selectedIndex] = displayRect;
displayRect.RectangleF = ScaleDown(displayRect.Rectangle);
startPoint = e.Location;
}
else if (CurrentMode == DrawMode.Resizing && selectedIndex >= 0)
{
Rectangle rect = displayRect.Rectangle;
switch (handleType)
{
case HandleType.TopLeft:
rect.X = e.X;
rect.Y = e.Y;
rect.Width = displayRect.Rectangle.Right - e.X;
rect.Height = displayRect.Rectangle.Bottom - e.Y;
break;
case HandleType.TopRight:
rect.Y = e.Y;
rect.Width = e.X - displayRect.Rectangle.Left;
rect.Height = displayRect.Rectangle.Bottom - e.Y;
break;
case HandleType.BottomLeft:
rect.X = e.X;
rect.Width = displayRect.Rectangle.Right - e.X;
rect.Height = e.Y - displayRect.Rectangle.Top;
break;
case HandleType.BottomRight:
rect.Width = e.X - displayRect.Rectangle.Left;
rect.Height = e.Y - displayRect.Rectangle.Top;
break;
}
if (rect.Width > 0 && rect.Height > 0)
{
displayRect.Rectangle = rect;
displayRect.RectangleF = ScaleDown(rect);
ShapeDictionary[selectedIndex] = displayRect;
}
}
}
else
{
if (selectedIndex >= 0)
{
handleType = displayRect.GetHandleType(e.Location);
switch (handleType)
{
case HandleType.TopLeft:
case HandleType.BottomRight:
container.Cursor = Cursors.SizeNWSE;
break;
case HandleType.TopRight:
case HandleType.BottomLeft:
container.Cursor = Cursors.SizeNESW;
break;
default:
container.Cursor = displayRect.Rectangle.Contains(e.Location) ?
Cursors.SizeAll : Cursors.Default;
break;
}
}
else
{
container.Cursor = Cursors.Default;
}
}
container.Invalidate();
}
private void Container_MouseUp(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
if (CurrentMode == DrawMode.Drawing && currentRect.Width > 0 && currentRect.Height > 0)
{
currentRect.RectangleF = ScaleDown(currentRect.Rectangle);
ShapeDictionary.Add(currentRect.ID, currentRect);
selectedIndex = currentRect.ID;
displayRect = currentRect;
startPoint = e.Location;
handleType = currentRect.GetHandleType(e.Location);
CurrentMode = handleType != HandleType.None ? DrawMode.Resizing : DrawMode.Moving;
}
CurrentMode = DrawMode.None;
container.Invalidate();
}
}
private void Container_Paint(object sender, PaintEventArgs e)
{
foreach (var shape in ShapeDictionary.Values)
{
if (shape.ID == selectedIndex)
{
shape.IsSelected = true;
shape.ShapeColor = Color.Red;
shape.HandleColor = Color.White;
}
else
{
shape.IsSelected = false;
shape.ShapeColor = Color.Blue;
shape.HandleColor = Color.White;
}
shape.DrawShapeWithHandles(e.Graphics);
}
if (currentRect == null) return;
if (CurrentMode == DrawMode.Drawing)
{
using (var brush = new SolidBrush(Color.FromArgb(50, 0, 0, 255)))
{
e.Graphics.FillRectangle(brush, currentRect.Rectangle);
}
e.Graphics.DrawRectangle(Pens.Blue, currentRect.Rectangle);
}
}
private void Container_MouseWheel(object sender, MouseEventArgs e)
{
if (e.Delta > 0) ZoomOut();
else if (e.Delta < 0) ZoomIn();
}
#endregion
}
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
- 20.
- 21.
- 22.
- 23.
- 24.
- 25.
- 26.
- 27.
- 28.
- 29.
- 30.
- 31.
- 32.
- 33.
- 34.
- 35.
- 36.
- 37.
- 38.
- 39.
- 40.
- 41.
- 42.
- 43.
- 44.
- 45.
- 46.
- 47.
- 48.
- 49.
- 50.
- 51.
- 52.
- 53.
- 54.
- 55.
- 56.
- 57.
- 58.
- 59.
- 60.
- 61.
- 62.
- 63.
- 64.
- 65.
- 66.
- 67.
- 68.
- 69.
- 70.
- 71.
- 72.
- 73.
- 74.
- 75.
- 76.
- 77.
- 78.
- 79.
- 80.
- 81.
- 82.
- 83.
- 84.
- 85.
- 86.
- 87.
- 88.
- 89.
- 90.
- 91.
- 92.
- 93.
- 94.
- 95.
- 96.
- 97.
- 98.
- 99.
- 100.
- 101.
- 102.
- 103.
- 104.
- 105.
- 106.
- 107.
- 108.
- 109.
- 110.
- 111.
- 112.
- 113.
- 114.
- 115.
- 116.
- 117.
- 118.
- 119.
- 120.
- 121.
- 122.
- 123.
- 124.
- 125.
- 126.
- 127.
- 128.
- 129.
- 130.
- 131.
- 132.
- 133.
- 134.
- 135.
- 136.
- 137.
- 138.
- 139.
- 140.
- 141.
- 142.
- 143.
- 144.
- 145.
- 146.
- 147.
- 148.
- 149.
- 150.
- 151.
- 152.
- 153.
- 154.
- 155.
- 156.
- 157.
- 158.
- 159.
- 160.
- 161.
- 162.
- 163.
- 164.
- 165.
- 166.
- 167.
- 168.
- 169.
- 170.
- 171.
- 172.
- 173.
- 174.
- 175.
- 176.
- 177.
- 178.
- 179.
- 180.
- 181.
- 182.
- 183.
- 184.
- 185.
- 186.
- 187.
- 188.
- 189.
- 190.
- 191.
- 192.
- 193.
- 194.
- 195.
- 196.
- 197.
- 198.
- 199.
- 200.
- 201.
- 202.
- 203.
- 204.
- 205.
- 206.
- 207.
- 208.
- 209.
- 210.
- 211.
- 212.
- 213.
- 214.
- 215.
- 216.
- 217.
- 218.
- 219.
- 220.
- 221.
- 222.
- 223.
- 224.
- 225.
- 226.
- 227.
- 228.
- 229.
- 230.
- 231.
- 232.
- 233.
- 234.
- 235.
- 236.
- 237.
- 238.
- 239.
- 240.
- 241.
- 242.
- 243.
- 244.
- 245.
- 246.
- 247.
- 248.
- 249.
- 250.
- 251.
- 252.
- 253.
- 254.
- 255.
- 256.
- 257.
- 258.
- 259.
- 260.
- 261.
- 262.
- 263.
- 264.
- 265.
- 266.
- 267.
- 268.
- 269.
- 270.
- 271.
- 272.
- 273.
- 274.
- 275.
- 276.
- 277.
- 278.
- 279.
- 280.
- 281.
- 282.
- 283.
- 284.
- 285.
- 286.
- 287.
- 288.
- 289.
- 290.
- 291.
- 292.
- 293.
- 294.
- 295.
- 296.
- 297.
- 298.
- 299.
- 300.
- 301.
- 302.
- 303.
- 304.
- 305.
- 306.
- 307.
- 308.
- 309.
- 310.
- 311.
- 312.
- 313.
- 314.
- 315.
- 316.
- 317.
- 318.
- 319.
- 320.
- 321.
- 322.
- 323.
- 324.
- 325.
- 326.
- 327.
- 328.
- 329.
- 330.
- 331.
- 332.
- 333.
- 334.
- 335.
- 336.
- 337.
- 338.
- 339.
- 340.
- 341.
- 342.
- 343.
- 344.
- 345.
- 346.
- 347.
- 348.
- 349.
- 350.
- 351.
- 352.
- 353.
- 354.
- 355.
- 356.
- 357.
- 358.
- 359.
- 360.
- 361.
- 362.
- 363.
- 364.
- 365.
- 366.
- 367.
- 368.
- 369.
- 370.
- 371.
- 372.
用到的枚举
用户界面代码
using CustomControls;
using Shapes;
using System;
using System.Drawing;
namespace CS学习之绘制形状
{
public partial class MainForm : WinFormBase
{
ShapeModule shapeModule;
string imageFile = AppDomain.CurrentDomain.BaseDirectory + "source.png";
public MainForm()
{
InitializeComponent();
this.CenterToParent();
shapeModule = new ShapeModule(uc_Canvas);
uc_Canvas.Image = Image.FromFile(imageFile);
}
private void btn_Draw_Click(object sender, System.EventArgs e)
{
shapeModule.CurrentMode = DrawMode.Drawing;
}
}
}
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
- 20.
- 21.
- 22.
- 23.
双缓存图像控件
用户界面

用户界面
- 该用户界面为前几期的内容创建,如想使用可翻阅前面的内容查看代码。
- 不使用该窗体也可以使用自定义的Form窗体,只需添加按钮,添加任意控件即可,注意设置Dock属性为Fill。
- 控件最好设置双缓冲,否则会出现界面闪烁。
- 设计缺陷:当用户自定义控件绘制图像时,如果也创建了下面实现的事件如鼠标按下事件(MouseDown),可能会起冲突。
结语
- 使用方法,将自定义控件创建在同一个命名空间下,点击生成无报错后,即可在工具箱中查看选择自定义控件。
- 拖拽到当前窗体即可。如果是创建自己的类库,并引用这个类库,引用时可能得报错原因,目标框架不同。
- 公众号:编程笔记in
最后
- 也可以关注微信公众号 [编程笔记in] 社区一起交流心得!
- 项目源码: gitee.com/li503560604/cshape-demos
1504

被折叠的 条评论
为什么被折叠?



