C# WinForms 自定义进度轴控件实现指南

苏见山
苏见山
发布时间:2026-10-13| 5人浏览过
原创

针对软件中长时间后台处理任务缺乏可视化反馈的问题,本文介绍一种基于 C# WinForms 开发的自定义进度轴(Time Axis)控件。该控件利用 GDI+ 技术绘制包含节点、连接线和文本标签的时间轴界面,支持水平与垂直两种布局,并通过事件机制实时更新当前执行阶段,使操作者能清晰掌握程序运行全局动态。

设计目标与准备条件

当应用程序需要执行耗时较长的后台处理时,提供一个直观的进度反馈能显著提升用户体验。本方案旨在构建一个可复用的 UserControl,其核心功能包括:

  • 多模式显示:支持横向(Horizontal)和纵向(Vertical)两种进度轴排列方式,适应不同 UI 布局需求。
  • GDI+ 高质量绘图:使用 Anti-aliasing(抗锯齿)技术确保线条平滑,提升视觉质感。
  • 事件驱动更新:通过订阅特定事件,由外部调用控制进度轴的步进状态,无需修改内部绘制逻辑。

开发环境需具备 .NET Framework 支持 Windows Forms 的基础库(如 System.Drawing)。建议在设计器或代码中准备好一个 Panel 容器作为进度轴的宿主。

核心属性与绘图配置

为了实现灵活的样式定制,首先定义一组静态只读字段用于管理绘图所需的画笔、字体及几何参数。这些参数决定了进度轴的外观风格。

// 定义绘图画笔:蓝色主线、绿色进度线、灰色背景线
static Pen p1 = new Pen(Color.Blue, 2);
static Pen p2 = new Pen(Color.Green, 3); // 当前进度高亮线
static Pen p3 = new Pen(Color.Gray, 1);   // 未激活背景线

// 定义文本字体
static Font f1 = new Font("微软雅黑", 9, FontStyle.Regular);

// 几何坐标常量
public static int CenterOfTheCircleX = 31; // 圆心 X 坐标
public static int CenterOfTheCircleY = 46; // 圆心 Y 坐标
public static int ItemStartX = 45;         // 标签文本起始 X
public static int CircleRadius = 9;        // 节点外圆半径
public static int PieRadius = 6;           // 节点内实心圆半径
public static int CircleSpace = 80;        // 节点间距

步骤一:初始化进度轴数据

进度轴的本质是一系列有序的任务步骤。使用 SortedDictionary<string, string> 来存储键值对,其中 Key 为步骤索引(用于排序),Value 为该步骤的描述文本。

public void LoadTimeAxis()
{
    // 1. 构建步骤字典
    SortedDictionary<string, string> sdict = new SortedDictionary<string, string>();
    sdict.Add("1", "读取配置");
    sdict.Add("2", "选择模板");
    sdict.Add("3", "确认数据");
    sdict.Add("4", "生成代码");
    
    // 2. 实例化控件,传入字典及模式(1代表纵向,0代表横向)
    uctlTimeAxis uta = new uctlTimeAxis(sdict, 1);
    
    // 3. 绑定点击事件回调(可选交互功能)
    // uta.lc = ... // 根据实际需求挂载代理
    
    // 4. 将控件添加到 Panel 容器中
    CommonFunction.AddForm3(splitContainer4.Panel2, uta);
}

第1步:添加控件到容器

为了保持界面整洁,通常将自定义 UserControl 嵌入到一个 Panel 中。以下辅助方法展示了如何清空旧内容并填新控件:

public static void AddForm3(Panel p, UserControl uc)
{
    p.Controls.Clear();     // 清理容器内原有控件
    p.Controls.Add(uc);     // 添加新控件
    uc.Dock = DockStyle.Fill; // 填满整个容器区域
}

步骤二:绘制纵向进度轴界面

绘制过程涉及 GDI+ 图形对象的创建。为保证性能,建议在重绘或初始化时使用 using (Graphics g = this.CreateGraphics()) 块,并在绘制前后设置高质量的绘图模式。

public void InitVerticalTimeAxis()
{
    try
    {
        using (Graphics g = this.CreateGraphics())
        {
            // 启用最高绘图质量
            g.SmoothingMode = SmoothingMode.HighQuality;
            g.InterpolationMode = InterpolationMode.HighQualityBicubic;
            g.CompositingQuality = CompositingQuality.HighQuality;

            int tempY = CenterOfTheCircleY;
            
            // 绘制“正在执行”标题文字
            g.DrawString("正在执行:", f1, Brushes.Black, 
                new PointF(CenterOfTheCircleX, 5));
            
            // 绘制背景基准线(灰色)
            int totalHeight = (sdict.Keys.Count - 1) * CircleSpace + CenterOfTheCircleY;
            g.DrawLine(p3, new Point(LineStartX, CenterOfTheCircleY), 
                      new Point(LineStartX, totalHeight));

            // 遍历字典绘制每个节点和标签
            foreach (var item in sdict.Keys)
            {
                // 1. 绘制外圈(灰色空心)
                g.FillEllipse(Brushes.Gray, 
                    CenterOfTheCircleX - CircleRadius, 
                    tempY - CircleRadius, 
                    CircleRadius * 2, CircleRadius * 2);
                
                // 2. 绘制内圈(白色实心,形成环状效果)
                g.FillEllipse(Brushes.White, 
                    CenterOfTheCircleX - PieRadius, 
                    tempY - PieRadius, 
                    PieRadius * 2, PieRadius * 2);
                
                // 3. 绘制文本标签
                g.DrawString(sdict[item], f1, Brushes.DarkGray, 
                    new PointF(ItemStartX, tempY - 10));
                
                // 4. (可选)添加不可见的 Label 控件以支持鼠标点击交互
                Label l = new Label();
                l.Name = item;
                l.Text = sdict[item];
                l.Location = new Point(ItemStartX, tempY - 10);
                l.Click += new EventHandler(l_Click); // 绑定点击事件
                this.Controls.Add(l);

                // 更新 Y 轴坐标偏移量
                tempY += CircleSpace;
            }
        }
    }
    catch (Exception exp)
    {
        // 记录日志或处理错误
    }
}

步骤三:实现进度步进与高亮

当后台任务完成当前步骤时,调用步进方法。该方法会根据当前的 Key 值,将对应之前的节点着色为绿色(表示已完成/进行中),后续节点保持灰色默认状态。

public void SetVerticalStep(object sender, KeyValueEventArgs e)
{
    if (string.IsNullOrEmpty(KeyValueEventArgs.Key))
        return;

    using (Graphics g = this.CreateGraphics())
    {
        // 同样开启高质量渲染
        g.SmoothingMode = SmoothingMode.HighQuality;
        g.InterpolationMode = InterpolationMode.HighQualityBicubic;

        int tempY = CenterOfTheCircleY;

        foreach (var item in sdict.Keys)
        {
            // 绘制当前进度的绿色文本
            g.DrawString(sdict[item], f1, Brushes.Green, 
                ItemStartX, tempY - 10);

            // 绘制绿色的圆圈边框
            g.DrawEllipse(Pens.Green, 
                CenterOfTheCircleX - CircleRadius, 
                tempY - CircleRadius, 
                CircleRadius * 2, CircleRadius * 2);

            // 绘制连接线至当前位置
            g.DrawLine(p2, new Point(LineStartX, LineStartY), 
                       new Point(LineStartX, tempY));

            // 填充绿色实心圆点
            g.FillEllipse(Brushes.Green, 
                CenterOfTheCircleX - PieRadius, 
                tempY - PieRadius, 
                PieRadius * 2, PieRadius * 2);

            // 如果到达指定节点,停止后续绘制(仅高亮当前及之前)
            if (item == KeyValueEventArgs.Key)
            {
                break;
            }

            tempY += CircleSpace;
        }
    }
}

关键数据结构说明

为了方便外部触发步进,封装了事件参数类 KeyValueEventArgs:

public class KeyValueEventArgs : EventArgs
{
    public static string Key { get; set; } = "";
    
    public KeyValueEventArgs(string s)
    {
        Key = s;
    }
}

完成判断与维护提示

至此,您已拥有一个支持基本动态渲染的 C# 进度轴控件。在实际使用中请注意以下几点:

  • 重绘性能:频繁调用 CreateGraphics() 可能导致闪烁。在生产环境中,建议改用 OnPaint 重写机制或双缓冲技术(DoubleBuffered = true)来提升刷新效率。
  • 静态变量陷阱:原文示例中使用了很多 static 修饰的属性(如 CenterOfTheCircleX)。若在同一窗体中部署多个进度轴实例,静态变量会导致所有实例共用同一套坐标和样式,产生冲突。建议将这些字段改为实例成员(移除 static)。
  • 内存释放:使用 using 语句包裹 Graphics 对象是良好的编程习惯,可防止 GDI 资源泄漏。

以上就是C# WinForms自定义进度轴控件实现的详细内容,更多关于C# UI控件开发及GDI+绘图的资料请关注本站其它相关文章!

相关标签:

免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。

Python 相关产品和应用

全部下载
Selenium

Selenium

4.51.0 · Windows

用于浏览器自动化和 Web 测试的 Python 工具。

scikit-learn

scikit-learn

1.9.1 · Windows

常用 Python 机器学习算法与模型评估工具库。

Black

Black

26.10.1 · Windows

强调一致性的 Python 自动代码格式化工具。

Ruff

Ruff

0.17.1 · macOS

由 Rust 编写的高速 Python 代码检查和格式化工具。

pytest

pytest

9.1.1 · Windows

简洁而强大的 Python 自动化测试框架。

FastAPI

FastAPI

0.146.0 · Windows

高性能 Python API 框架,支持类型提示和自动接口文档。

Flask

Flask

3.1.3 · Windows

轻量灵活的 Python Web 应用框架。

Django

Django

6.1.2 · Windows

成熟的 Python Web 框架,适合构建内容站点和业务系统。

Spyder

Spyder

6.1.7 · Windows

面向科学计算与数据分析的 Python 集成开发环境。

SciPy

SciPy

1.18.1 · Windows

面向科学、工程和技术计算的 Python 算法库。