Sorry, your browser cannot access this site
This page requires browser support (enable) JavaScript
Learn more >

一、控件概述

1. 什么是控件

在 Csharp 桌面开发中,控件(Control) 是构成用户界面的基本元素,如按钮、文本框、下拉框、表格等。用户通过控件与程序交互,开发者通过设置控件属性和响应事件来实现业务逻辑。

控件通常继承自 System.Windows.Forms.Control(WinForms)或 System.Windows.UIElement(WPF),具备位置、大小、可见性、启用状态等通用特性。

2. WinForms 与 WPF 控件

框架 控件库命名空间 特点
WinForms System.Windows.Forms 拖拽即用,上手快,工控上位机常见
WPF System.Windows.Controls XAML 声明,数据绑定强,界面表现力好

本博客《WPF基础知识》已介绍 WPF 布局与常用控件,本文重点讲解 WinForms 控件,并补充自定义控件与通用开发思路。

3. 控件的三要素

要素 说明 示例
属性(Property) 描述控件外观与行为 TextEnabledVisible
事件(Event) 响应用户或系统动作 ClickTextChangedSelectedIndexChanged
方法(Method) 控件可调用的操作 Focus()Clear()Show()

二、创建与使用控件

1. 可视化设计器

在 Visual Studio 中创建 WinForms 项目后,从工具箱拖拽控件到窗体,设计器会自动生成布局代码。

2. 代码动态创建

1
2
3
4
5
6
7
8
var btnStart = new Button
{
Text = "开始",
Location = new Point(20, 20),
Size = new Size(100, 35)
};
btnStart.Click += BtnStart_Click;
Controls.Add(btnStart);

3. 命名规范

  • 控件 Name 属性建议有意义,如 btnConnecttxtPortcmbBaudRate
  • 常见前缀:btn 按钮、txt 文本框、lbl 标签、cmb 下拉框、dgv 表格

三、常用基础控件

1. Button(按钮)

触发操作的最基本控件。

1
2
3
4
private void btnSave_Click(object sender, EventArgs e)
{
MessageBox.Show("保存成功");
}

常用属性:TextEnabledDialogResult(用于对话框返回值)

2. Label(标签)

显示静态或动态文字,一般不可编辑。

1
2
lblStatus.Text = "已连接";
lblStatus.ForeColor = Color.Green;

3. TextBox(文本框)

单行或多行文本输入。

属性 说明
Text 文本内容
Multiline 是否多行
PasswordChar 密码掩码字符
ReadOnly 只读
MaxLength 最大字符数
1
2
txtIpAddress.Text = "192.168.1.100";
string input = txtPort.Text.Trim();

常用事件:TextChanged(文本变化时触发)

4. RichTextBox(富文本框)

支持多行、颜色、字体等富文本显示,适合日志输出。

1
2
3
rtbLog.AppendText($"[{DateTime.Now:HH:mm:ss}] 连接成功\r\n");
rtbLog.SelectionColor = Color.Red;
rtbLog.AppendText("错误:端口被占用\r\n");

5. CheckBox(复选框)

多选场景,返回 Checked 布尔值。

1
2
3
4
if (chkAutoConnect.Checked)
{
ConnectDevice();
}

6. RadioButton(单选按钮)

同一组内互斥选择,通常放在 GroupBoxPanel 中。

1
2
if (rbTcp.Checked) mode = "TCP";
else if (rbUdp.Checked) mode = "UDP";

7. ComboBox(下拉框)

从预设列表中选择一项。

1
2
3
cmbBaudRate.Items.AddRange(new object[] { "9600", "19200", "115200" });
cmbBaudRate.SelectedIndex = 0;
string baud = cmbBaudRate.SelectedItem?.ToString() ?? "9600";

常用属性:DropDownStyleDropDownList 禁止手动输入)

常用事件:SelectedIndexChanged

四、容器与布局控件

1. Panel(面板)

用于分组和承载其他控件,支持滚动。

1
2
panelMain.Controls.Add(btnStart);
panelMain.AutoScroll = true;

2. GroupBox(分组框)

带标题边框的容器,常用于选项分组。

1
2
<!-- 设计器中拖拽即可,代码中: -->
groupBoxSerial.Controls.Add(cmbPort);

3. TabControl(选项卡)

多页界面切换,适合功能模块较多的上位机软件。

1
tabControl1.SelectedTab = tabPageSettings;

4. TableLayoutPanel / FlowLayoutPanel

  • TableLayoutPanel:表格式网格布局
  • FlowLayoutPanel:流式自动排列

工控界面中,用 TableLayoutPanel 可快速实现整齐的表单布局。

五、列表与表格控件

1. ListBox(列表框)

展示一列数据,支持单选或多选。

1
2
3
listBoxDevices.Items.Add("COM1");
listBoxDevices.Items.Add("COM3");
listBoxDevices.SelectedIndex = 0;

2. ListView(列表视图)

支持大图标、小图标、列表、详细信息等多种显示模式。

1
2
3
4
5
6
listViewFiles.View = View.Details;
listViewFiles.Columns.Add("文件名", 200);
listViewFiles.Columns.Add("大小", 80);
var item = new ListViewItem("config.bin");
item.SubItems.Add("4 KB");
listViewFiles.Items.Add(item);

3. DataGridView(数据表格)

最常用的表格控件,适合展示设备列表、采集数据、配置参数等。

1
2
3
4
5
dataGridView1.AutoGenerateColumns = false;
dataGridView1.Columns.Add("Name", "设备名");
dataGridView1.Columns.Add("Status", "状态");
dataGridView1.Rows.Add("设备A", "在线");
dataGridView1.Rows.Add("设备B", "离线");

绑定数据源:

1
dataGridView1.DataSource = deviceList;

常用属性:

属性 说明
ReadOnly 只读
AllowUserToAddRows 允许用户新增行
SelectionMode 选择模式
AutoSizeColumnsMode 列宽自适应

4. TreeView(树形视图)

层级结构展示,如文件目录、设备分组。

1
2
3
4
var root = treeView1.Nodes.Add("产线A");
root.Nodes.Add("工位1");
root.Nodes.Add("工位2");
treeView1.ExpandAll();

六、日期、数值与进度控件

1. DateTimePicker(日期选择器)

1
DateTime selected = dtpStart.Value;

2. NumericUpDown(数值调节器)

1
2
3
4
numericUpDown1.Minimum = 1;
numericUpDown1.Maximum = 65535;
numericUpDown1.Value = 502;
int port = (int)numericUpDown1.Value;

3. ProgressBar(进度条)

1
2
3
progressBar1.Minimum = 0;
progressBar1.Maximum = 100;
progressBar1.Value = 45;

4. TrackBar(滑动条)

适合音量、阈值等连续值调节。

七、菜单与工具栏

1. MenuStrip(菜单栏)

1
2
3
4
5
var menuFile = new ToolStripMenuItem("文件");
var menuOpen = new ToolStripMenuItem("打开");
menuOpen.Click += MenuOpen_Click;
menuFile.DropDownItems.Add(menuOpen);
menuStrip1.Items.Add(menuFile);

2. ToolStrip(工具栏)

放置常用图标按钮,如连接、断开、保存。

3. StatusStrip(状态栏)

显示连接状态、时间、提示信息。

1
toolStripStatusLabel1.Text = "就绪";

4. ContextMenuStrip(右键菜单)

绑定到控件右键操作。

1
txtLog.ContextMenuStrip = contextMenuStrip1;

八、对话框控件

1. MessageBox(消息框)

1
2
3
4
5
6
7
8
9
10
var result = MessageBox.Show(
"确定要断开连接吗?",
"确认",
MessageBoxButtons.YesNo,
MessageBoxIcon.Question);

if (result == DialogResult.Yes)
{
Disconnect();
}

2. OpenFileDialog / SaveFileDialog

1
2
3
4
5
6
7
8
9
10
using var dialog = new OpenFileDialog
{
Filter = "固件文件|*.bin;*.hex|所有文件|*.*"
};

if (dialog.ShowDialog() == DialogResult.OK)
{
string filePath = dialog.FileName;
LoadFirmware(filePath);
}

3. FolderBrowserDialog

选择文件夹路径,常用于日志目录、导出路径配置。

4. ColorDialog / FontDialog

颜色与字体选择,用于界面主题或日志高亮配置。

九、定时与后台任务控件

1. Timer(定时器)

WinForms 中常用的 System.Windows.Forms.Timer,在 UI 线程触发 Tick 事件。

1
2
3
4
5
6
7
8
timerPoll.Interval = 1000; // 毫秒
timerPoll.Tick += TimerPoll_Tick;
timerPoll.Start();

private void TimerPoll_Tick(object? sender, EventArgs e)
{
RefreshDeviceStatus();
}

适合界面刷新、定时采集;耗时操作应放后台线程,避免阻塞 UI。

2. BackgroundWorker(后台工作者)

在后台线程执行任务并回报进度(.NET Framework 常用,新项目可用 Task + async/await 替代)。

十、自定义控件

1. UserControl(用户控件)

将多个已有控件组合成可复用模块。

1
2
3
4
5
6
7
8
9
10
public partial class SerialPortPanel : UserControl
{
public SerialPortPanel()
{
InitializeComponent();
}

public string SelectedPort => cmbPort.Text;
public int BaudRate => int.Parse(cmbBaudRate.Text);
}

适用场景:串口配置面板、设备状态卡片、重复使用的表单区块。

2. 继承 Control 自定义绘制

需要完全自定义外观时,继承 Control 并重写 OnPaint

1
2
3
4
5
6
7
8
9
10
11
public class StatusIndicator : Control
{
public bool IsOnline { get; set; }

protected override void OnPaint(PaintEventArgs e)
{
var color = IsOnline ? Color.LimeGreen : Color.Gray;
using var brush = new SolidBrush(color);
e.Graphics.FillEllipse(brush, 2, 2, Width - 4, Height - 4);
}
}

3. 自定义控件的价值

  • 提高代码复用率
  • 统一交互与样式
  • 便于团队分工与维护

十一、跨线程更新 UI

WinForms 控件只能在创建它们的 UI 线程上访问。后台线程更新界面需使用 InvokeBeginInvoke

1
2
3
4
5
6
7
8
9
private void OnDataReceived(string data)
{
if (txtLog.InvokeRequired)
{
txtLog.BeginInvoke(() => OnDataReceived(data));
return;
}
txtLog.AppendText(data + Environment.NewLine);
}

.NET 6+ 也可使用 txtLog.Invoke(() => txtLog.AppendText(data))

这是串口通讯、网络回调、烧录进度等上位机场景中最常见的坑之一。

十二、控件开发最佳实践

1. 布局

  • 使用 AnchorDock 实现窗体缩放自适应
  • 复杂界面优先 TableLayoutPanel,避免绝对坐标堆砌
  • 设置 MinimumSize 防止窗口缩得过小

2. 事件处理

  • 事件方法保持简短,业务逻辑抽到独立类
  • 避免在 TextChanged 中做重型计算
  • 重复触发事件时注意防抖(如搜索框输入)

3. 数据展示

  • 大量数据优先 DataGridView + 数据绑定
  • 日志输出用 RichTextBox,注意定期清理避免内存膨胀
  • 列表频繁刷新时考虑批量更新或虚拟模式

4. 用户体验

  • 长操作期间禁用按钮并显示 Cursor.WaitCursor
  • ProgressBar 或状态栏反馈进度
  • 输入校验在提交前完成,配合 ErrorProvider 提示

5. 与 MVVM 的关系

WinForms 以代码后置 + 事件驱动为主;WPF 则更推荐 MVVM 与数据绑定。若项目规模较大、界面逻辑复杂,可参考本博客《MVVM设计模式》与《WPF基础知识》。

十三、上位机场景控件选型参考

功能 推荐控件
串口/波特率选择 ComboBox
连接/断开/烧录 Button
通讯日志 RichTextBox
设备列表 DataGridView / ListView
烧录进度 ProgressBar + Label
参数配置 NumericUpDown / TextBox
定时轮询 Timer
固件文件选择 OpenFileDialog
多模块界面 TabControl
状态指示 自定义 UserControlPanel

结合《网线烧录芯片与Csharp传输实现》,上述控件即可搭建完整的设备通讯与烧录上位机界面。

十四、常见问题

现象 原因 处理
跨线程操作无效 非 UI 线程访问控件 使用 Invoke / BeginInvoke
界面卡死 UI 线程执行耗时操作 放后台线程,完成后回调 UI
数据绑定不刷新 未实现 INotifyPropertyChanged 绑定对象实现属性通知
窗体缩放布局乱 未设置 Anchor/Dock 使用布局容器与锚定
DataGridView 闪烁 频繁整表刷新 暂停布局或局部更新
Timer 不触发 未 Start 或 Interval 为 0 检查启停逻辑

十五、小结

Csharp 控件是桌面应用开发的基础积木。WinForms 控件上手快、生态成熟,适合工控上位机、企业内部工具等场景;WPF 控件则在数据绑定与界面表现力上更胜一筹。

学习建议:

  1. 先掌握 ButtonTextBoxComboBoxLabel 等基础控件
  2. 再学 DataGridViewTabControl 等复合界面控件
  3. 理解属性、事件、布局与跨线程更新
  4. 通过 UserControl 封装复用模块
  5. 结合《Csharp基础知识》《WPF基础知识》与实战项目深化

熟练运用控件,才能高效搭建功能完整、体验良好的 Csharp 桌面应用。

评论