支轴事件任务线程执行工序路径的图表组件

开发一个主页面包含主子节点表格的工序路径的图表控件的页面,工序管理操作界面带拖拽式控件,组支轴事件任务线程执行层面,事件组轴和线程支组件组装工序路径资源功能模块,相关菜单页面SqlSugar函数方法预备7,15组工序成组数据,项目主要使用GDI绘图绘制,界面的图表控件尽量封装实现,实现本地文件化数据库的Winform端的代码实现组件

WinForm 组支轴主子节点工序管理完整工程

项目整体说明

核心技术栈

WinForm (.NET Framework4.8) + SqlSugar + SQLite 本地文件数据库 + GDI + 独立封装图表控件 + BackgroundWorker 后台任务线程

业务需求落地

  1. 预置15 组主工序、7 组配套子工序成组业务数据;
  2. 主页面双视图:主子节点 DataGridView 表格 + GDI 工序路径流程图控件
  3. 独立拖拽工序管理窗体,GDI 自绘拖拽列表,拖拽调整工序路径顺序,自动入库;
  4. 后台线程任务模块:异步执行组轴 / 支组件组装仿真,全程不阻塞 UI;
  5. 顶部菜单栏多页面入口:图表主页、拖拽管理、工序资源编辑、启动组装任务;
  6. 全代码兼容 C#7.3,移除is not等高版本语法,杜绝 CS8370 编译报错;
  7. GDI 图表控件完全封装,横向渲染主子工序流转、资源、耗时、流转箭头,无第三方图表库。

一、NuGet 依赖安装命令

plaintext

复制代码
Install-Package SqlSugar
Install-Package System.Data.SQLite.Core

二、业务实体类(主工序、子工序、组装任务)

csharp

运行

复制代码
using SqlSugar;
using System.Collections.Generic;

/// <summary>组支轴主工序(15组主数据)</summary>
[SugarTable("GroupAxisMainProcess")]
public class GroupAxisMainProcess
{
    [SugarColumn(IsPrimaryKey = true, IsIdentity = true)]
    public int Id { get; set; }
    /// <summary>主工序名称</summary>
    public string MainProcessName { get; set; }
    /// <summary>支轴类型分类</summary>
    public string AxisCategory { get; set; }
}

/// <summary>支组件子工序(7组配套子工序数据,关联主工序)</summary>
[SugarTable("SubComponentStep")]
public class SubComponentStep
{
    [SugarColumn(IsPrimaryKey = true, IsIdentity = true)]
    public int Id { get; set; }
    /// <summary>归属主工序ID</summary>
    public int MainProcessId { get; set; }
    /// <summary>子组件工序名称</summary>
    public string StepName { get; set; }
    /// <summary>工序资源:设备、工装、操作工</summary>
    public string ResourceInfo { get; set; }
    /// <summary>工序耗时(分钟)</summary>
    public int CostMinute { get; set; }
    /// <summary>工序路径排序号(拖拽更新)</summary>
    public int SortIndex { get; set; }
}

/// <summary>后台线程执行的组件组装任务模型</summary>
public class AxisAssemblyTask
{
    public int MainProcessId { get; set; }
    public string TaskTitle { get; set; }
    public List<SubComponentStep> StepCollection { get; set; }
}

三、SqlSugar 本地数据库工具类(预置 15 主 7 子成组数据)

csharp

运行

复制代码
using SqlSugar;
using System;
using System.Collections.Generic;
using System.IO;

public static class AxisDbHelper
{
    // 本地SQLite数据库文件路径
    private static readonly string DbFilePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "AxisProcessLocalDB.db");

    /// <summary>获取SqlSugar数据库客户端实例</summary>
    public static SqlSugarClient GetDbClient()
    {
        ConnectionConfig cfg = new ConnectionConfig()
        {
            ConnectionString = $"Data Source={DbFilePath}",
            DbType = DbType.Sqlite,
            IsAutoCloseConnection = true,
            InitKeyType = InitKeyType.Attribute
        };
        return new SqlSugarClient(cfg);
    }

    /// <summary>初始化数据库、自动建表、插入15组主工序+7组子工序测试数据</summary>
    public static void InitDatabase()
    {
        SqlSugarClient db = GetDbClient();
        // 自动根据实体创建数据表
        db.CodeFirst.InitTables<GroupAxisMainProcess, SubComponentStep>();

        // 已有数据直接跳过初始化,防止重复插入
        if (db.Queryable<GroupAxisMainProcess>().Count() > 0)
            return;

        #region 15套组支轴主工序数据
        List<GroupAxisMainProcess> mainProcessList = new List<GroupAxisMainProcess>()
        {
            new(){MainProcessName="轻型短主轴总装",AxisCategory="轻型短轴"},
            new(){MainProcessName="轻型加长主轴总装",AxisCategory="轻型长轴"},
            new(){MainProcessName="中型实心切削主轴",AxisCategory="中型实心轴"},
            new(){MainProcessName="中型空心液压主轴",AxisCategory="中型空心轴"},
            new(){MainProcessName="重型法兰传动主轴",AxisCategory="重型法兰轴"},
            new(){MainProcessName="重型多段组合主轴",AxisCategory="重型多段轴"},
            new(){MainProcessName="微型精密走心主轴",AxisCategory="微型精密轴"},
            new(){MainProcessName="微型偏心磨削主轴",AxisCategory="微型偏心轴"},
            new(){MainProcessName="高速切削加工主轴",AxisCategory="高速切削轴"},
            new(){MainProcessName="低速重载滚压主轴",AxisCategory="低速重载轴"},
            new(){MainProcessName="齿轮输出传动主轴",AxisCategory="齿轮输出轴"},
            new(){MainProcessName="同步带驱动传动轴",AxisCategory="同步传动轴"},
            new(){MainProcessName="液压内置动力主轴",AxisCategory="液压主轴"},
            new(){MainProcessName="气动高速打磨主轴",AxisCategory="气动主轴"},
            new(){MainProcessName="磨床砂轮专用主轴",AxisCategory="砂轮主轴"}
        };
        db.Insertable(mainProcessList).ExecuteCommand();
        #endregion

        #region 7套配套子工序步骤数据
        List<SubComponentStep> subStepList = new List<SubComponentStep>()
        {
            new(){MainProcessId=1,StepName="轴芯粗车加工",ResourceInfo="数控车床、合金刀具",CostMinute=17,SortIndex=1},
            new(){MainProcessId=1,StepName="双轴承液压压装",ResourceInfo="液压压装机、轴承工装",CostMinute=13,SortIndex=2},
            new(){MainProcessId=3,StepName="实心轴外圆精磨",ResourceInfo="数控外圆磨床、树脂砂轮",CostMinute=24,SortIndex=1},
            new(){MainProcessId=5,StepName="法兰盘过盈热套",ResourceInfo="中频加热炉、扭力扳手",CostMinute=32,SortIndex=1},
            new(){MainProcessId=7,StepName="微型轴走心精车",ResourceInfo="走心车床、微型硬质刀具",CostMinute=11,SortIndex=1},
            new(){MainProcessId=9,StepName="高速主轴动平衡校正",ResourceInfo="高速动平衡检测仪",CostMinute=34,SortIndex=1},
            new(){MainProcessId=15,StepName="砂轮锁紧组件装配",ResourceInfo="扭矩扳手、平衡配重块",CostMinute=19,SortIndex=1}
        };
        db.Insertable(subStepList).ExecuteCommand();
        #endregion
    }

    #region 数据库通用CRUD封装方法
    /// <summary>查询全部15组主工序</summary>
    public static List<GroupAxisMainProcess> QueryAllMainProcess()
    {
        return GetDbClient().Queryable<GroupAxisMainProcess>().ToList();
    }

    /// <summary>根据主工序ID查询关联子工序,按排序号升序</summary>
    public static List<SubComponentStep> QuerySubStepByMainId(int mainId)
    {
        return GetDbClient().Queryable<SubComponentStep>()
            .Where(s => s.MainProcessId == mainId)
            .OrderBy(s => s.SortIndex)
            .ToList();
    }

    /// <summary>拖拽工序后更新排序号</summary>
    public static void UpdateStepSort(int stepId, int newSortNo)
    {
        GetDbClient().Updateable<SubComponentStep>()
            .Set(s => s.SortIndex, newSortNo)
            .Where(s => s.Id == stepId)
            .ExecuteCommand();
    }

    /// <summary>修改子工序资源信息与耗时</summary>
    public static void UpdateStepResource(int stepId, string resource, int costTime)
    {
        GetDbClient().Updateable<SubComponentStep>()
            .Set(s => s.ResourceInfo, resource)
            .Set(s => s.CostMinute, costTime)
            .Where(s => s.Id == stepId)
            .ExecuteCommand();
    }

    /// <summary>新增子工序步骤</summary>
    public static void InsertNewSubStep(SubComponentStep step)
    {
        GetDbClient().Insertable(step).ExecuteCommand();
    }
    #endregion
}

四、封装 GDI 工序路径图表控件(主子工序流程图)

csharp

运行

复制代码
using System.Collections.Generic;
using System.Drawing;
using System.Windows.Forms;

/// <summary>GDI完整封装控件:主子工序路径资源横向流程图</summary>
public class GdiAxisProcessFlowChart : Control
{
    // 绑定子工序数据源
    public List<SubComponentStep> StepDataSource { get; set; } = new List<SubComponentStep>();

    public GdiAxisProcessFlowChart()
    {
        DoubleBuffered = true;
        // 开启自绘、消除闪烁
        SetStyle(ControlStyles.UserPaint | ControlStyles.AllPaintingInWmPaint | ControlStyles.DoubleBuffer, true);
        Font = new Font("微软雅黑", 9);
    }

    protected override void OnPaint(PaintEventArgs e)
    {
        Graphics g = e.Graphics;
        g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
        g.Clear(Color.WhiteSmoke);

        // 无数据提示文字
        if (StepDataSource == null || StepDataSource.Count == 0)
        {
            g.DrawString("请在左侧主工序表格选择行,加载子工序路径图表", Font, Brushes.Gray, 36, 36);
            return;
        }

        // 绘图基础尺寸参数
        int startX = 32;
        int blockWidth = 162;
        int blockHeight = 76;
        int blockGap = 28;
        int startY = 44;

        for (int i = 0; i < StepDataSource.Count; i++)
        {
            SubComponentStep step = StepDataSource[i];
            Rectangle stepBlock = new Rectangle(startX + i * (blockWidth + blockGap), startY, blockWidth, blockHeight);

            // 绘制工序块底色+边框
            g.FillRectangle(Brushes.LightSkyBlue, stepBlock);
            g.DrawRectangle(Pens.DarkSlateGray, stepBlock);

            // 绘制工序文字信息:工序名称、资源、耗时
            g.DrawString($"子工序:{step.StepName}", Font, Brushes.Black, stepBlock.X + 8, stepBlock.Y + 8);
            g.DrawString($"配套资源:{step.ResourceInfo}", Font, Brushes.DarkGreen, stepBlock.X + 8, stepBlock.Y + 30);
            g.DrawString($"工序耗时:{step.CostMinute} min", Font, Brushes.DarkOrange, stepBlock.X + 8, stepBlock.Y + 52);

            // 工序之间红色流转箭头
            if (i != StepDataSource.Count - 1)
            {
                Point lineStart = new Point(stepBlock.Right, stepBlock.Y + blockHeight / 2);
                Point lineEnd = new Point(stepBlock.Right + blockGap, stepBlock.Y + blockHeight / 2);
                g.DrawLine(Pens.Red, lineStart, lineEnd);
                // 简易箭头头部
                g.DrawLine(Pens.Red, lineEnd.X - 7, lineEnd.Y - 6, lineEnd.X, lineEnd.Y);
                g.DrawLine(Pens.Red, lineEnd.X - 7, lineEnd.Y + 6, lineEnd.X, lineEnd.Y);
            }
        }
    }
}

五、封装 GDI 拖拽工序管理控件

csharp

运行

复制代码
using System.Collections.Generic;
using System.Drawing;
using System.Windows.Forms;

/// <summary>GDI自绘拖拽控件:子工序拖拽调整路径排序</summary>
public class GdiStepDragListControl : Control
{
    public List<SubComponentStep> StepItemList { get; set; } = new List<SubComponentStep>();
    private int _dragIndex = -1;
    private bool _isDragging = false;

    // 拖拽保存完成回调事件
    public event Action SortSaveComplete;

    public GdiStepDragListControl()
    {
        DoubleBuffered = true;
        Cursor = Cursors.Hand;
        SetStyle(ControlStyles.UserPaint | ControlStyles.AllPaintingInWmPaint, true);
    }

    protected override void OnPaint(PaintEventArgs e)
    {
        Graphics g = e.Graphics;
        g.Clear(Color.White);

        for (int i = 0; i < StepItemList.Count; i++)
        {
            SubComponentStep step = StepItemList[i];
            int itemTopY = 14 + i * 86;
            Rectangle itemRect = new Rectangle(14, itemTopY, Width - 38, 78);

            // 拖拽项高亮底色区分
            Brush backBrush = _dragIndex == i ? Brushes.LightBlue : Brushes.WhiteSmoke;
            g.FillRectangle(backBrush, itemRect);
            g.DrawRectangle(Pens.Gray, itemRect);

            g.DrawString($"排序号:{step.SortIndex} {step.StepName}", Font, Brushes.Black, itemRect.X + 10, itemRect.Y + 10);
            g.DrawString($"资源:{step.ResourceInfo}", Font, Brushes.DarkGreen, itemRect.X + 10, itemRect.Y + 34);
            g.DrawString($"耗时:{step.CostMinute} min", Font, Brushes.DarkOrange, itemRect.X + 10, itemRect.Y + 58);
        }
    }

    protected override void OnMouseDown(MouseEventArgs e)
    {
        for (int i = 0; i < StepItemList.Count; i++)
        {
            int itemTopY = 14 + i * 86;
            if (e.Y >= itemTopY && e.Y <= itemTopY + 78)
            {
                _dragIndex = i;
                _isDragging = true;
                break;
            }
        }
    }

    protected override void OnMouseMove(MouseEventArgs e)
    {
        if (!_isDragging) return;
        int targetIndex = (e.Y - 14) / 86;
        if (targetIndex >= 0 && targetIndex < StepItemList.Count && targetIndex != _dragIndex)
        {
            // 交换集合元素实现拖拽换位
            SubComponentStep temp = StepItemList[_dragIndex];
            StepItemList.RemoveAt(_dragIndex);
            StepItemList.Insert(targetIndex, temp);
            _dragIndex = targetIndex;
            Invalidate();
        }
    }

    protected override void OnMouseUp(MouseEventArgs e)
    {
        if (_isDragging)
        {
            // 批量更新排序号并同步数据库
            for (int i = 0; i < StepItemList.Count; i++)
            {
                StepItemList[i].SortIndex = i + 1;
                AxisDbHelper.UpdateStepSort(StepItemList[i].Id, StepItemList[i].SortIndex);
            }
            SortSaveComplete?.Invoke();
        }
        _isDragging = false;
        _dragIndex = -1;
        Invalidate();
    }
}

六、后台组件组装任务线程管理器

csharp

运行

复制代码
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Threading;

/// <summary>组轴、支组件后台异步组装任务线程管理模块</summary>
public class AxisAssemblyTaskManager
{
    private readonly BackgroundWorker _taskWorker = new BackgroundWorker();

    public AxisAssemblyTaskManager()
    {
        _taskWorker.DoWork += TaskBackgroundExecute;
        _taskWorker.RunWorkerCompleted += TaskExecuteFinish;
    }

    public AxisAssemblyTask CurrentRunningTask { get; set; }
    public Action<AxisAssemblyTask> TaskFinishCallback { get; set; }

    /// <summary>启动后台组装任务,校验任务运行状态</summary>
    public void StartAssemblyTask(AxisAssemblyTask task)
    {
        if (_taskWorker.IsBusy)
        {
            throw new Exception("当前存在正在执行的组件组装任务,请等待任务完成后再新建!");
        }
        CurrentRunningTask = task;
        _taskWorker.RunWorkerAsync();
    }

    // 后台线程执行仿真逻辑
    private void TaskBackgroundExecute(object sender, DoWorkEventArgs e)
    {
        AxisAssemblyTask task = CurrentRunningTask;
        foreach (SubComponentStep step in task.StepCollection)
        {
            Thread.Sleep(step.CostMinute * 120);
        }
        e.Result = task;
    }

    // 任务完成回调,自动跨线程访问UI
    private void TaskExecuteFinish(object sender, RunWorkerCompletedEventArgs e)
    {
        if (e.Error != null) return;
        AxisAssemblyTask finishTask = e.Result as AxisAssemblyTask;
        TaskFinishCallback?.Invoke(finishTask);
    }
}

七、主窗体(主子表格 + GDI 图表双视图主页面 + 顶部菜单)

csharp

运行

复制代码
using System;
using System.Collections.Generic;
using System.Windows.Forms;

public partial class MainForm : Form
{
    private readonly GdiAxisProcessFlowChart _flowChartCtrl;
    private DataGridView _dgvMainProcess;
    private DataGridView _dgvSubStep;
    private readonly AxisAssemblyTaskManager _assemblyTaskManager;
    private SplitContainer _mainSplit;

    public MainForm()
    {
        InitializeComponent();
        Text = "组支轴主子节点工序管理系统|15主7子成组工序数据";
        Size = new Size(1300, 680);
        StartPosition = FormStartPosition.CenterScreen;

        // 初始化本地数据库,自动生成文件+预置数据
        AxisDbHelper.InitDatabase();
        // 初始化后台组装任务管理器
        _assemblyTaskManager = new AxisAssemblyTaskManager();
        _assemblyTaskManager.TaskFinishCallback = GlobalTaskFinishHandler;

        // 初始化GDI流程图控件
        _flowChartCtrl = new GdiAxisProcessFlowChart();
        BuildTopMenuStrip();
        InitMasterDetailTableLayout();
        LoadAllMainProcessToTable();
    }

    #region 顶部菜单栏构建
    private void BuildTopMenuStrip()
    {
        MenuStrip topMenu = new MenuStrip();
        ToolStripMenuItem menuChartPage = new ToolStripMenuItem("主子工序图表主页");
        ToolStripMenuItem menuDragSort = new ToolStripMenuItem("工序拖拽排序管理");
        ToolStripMenuItem menuResourceEdit = new ToolStripMenuItem("工序资源编辑");
        ToolStripMenuItem menuStartAssembly = new ToolStripMenuItem("启动后台组件组装任务");

        menuChartPage.Click += (s, e) => InitMasterDetailTableLayout();
        menuDragSort.Click += (s, e) => new DragSortWindow().ShowDialog(this);
        menuResourceEdit.Click += (s, e) => new ResourceEditWindow().ShowDialog(this);
        menuStartAssembly.Click += StartAssemblyTaskMenuClick;

        topMenu.Items.Add(menuChartPage);
        topMenu.Items.Add(menuDragSort);
        topMenu.Items.Add(menuResourceEdit);
        topMenu.Items.Add(menuStartAssembly);

        MainMenuStrip = topMenu;
        this.Controls.Add(topMenu);
    }
    #endregion

    #region 主子表格 + GDI图表页面布局
    private void InitMasterDetailTableLayout()
    {
        this.Controls.Clear();
        BuildTopMenuStrip();

        // 外层水平分割器:左侧表格区域,右侧GDI图表区域
        SplitContainer outerSplit = new SplitContainer();
        outerSplit.Dock = DockStyle.Fill;
        outerSplit.SplitterDistance = 420;

        // 左侧垂直分割:上主工序表格,下子工序表格
        _mainSplit = new SplitContainer();
        _mainSplit.Dock = DockStyle.Fill;
        _mainSplit.Orientation = Orientation.Vertical;
        _mainSplit.SplitterDistance = 320;

        // 主工序DataGridView
        _dgvMainProcess = new DataGridView();
        _dgvMainProcess.Dock = DockStyle.Fill;
        _dgvMainProcess.ReadOnly = true;
        _dgvMainProcess.AllowUserToAddRows = false;
        _dgvMainProcess.SelectionMode = DataGridViewSelectionMode.FullRowSelect;
        _dgvMainProcess.RowHeadersVisible = false;

        // 子工序DataGridView
        _dgvSubStep = new DataGridView();
        _dgvSubStep.Dock = DockStyle.Fill;
        _dgvSubStep.ReadOnly = true;
        _dgvSubStep.AllowUserToAddRows = false;
        _dgvSubStep.SelectionMode = DataGridViewSelectionMode.FullRowSelect;
        _dgvSubStep.RowHeadersVisible = false;

        // 绑定选中主工序事件,刷新子表格与GDI图表
        _dgvMainProcess.SelectionChanged += DgvMainProcess_SelectionChanged;

        // 组装布局
        _mainSplit.Panel1.Controls.Add(_dgvMainProcess);
        _mainSplit.Panel2.Controls.Add(_dgvSubStep);
        outerSplit.Panel1.Controls.Add(_mainSplit);
        outerSplit.Panel2.Controls.Add(_flowChartCtrl);
        this.Controls.Add(outerSplit);
    }

    // 加载全部15组主工序到主表格
    private void LoadAllMainProcessToTable()
    {
        List<GroupAxisMainProcess> mainList = AxisDbHelper.QueryAllMainProcess();
        _dgvMainProcess.DataSource = mainList;
    }

    // 主表格选中行切换,刷新子表格与流程图
    private void DgvMainProcess_SelectionChanged(object sender, EventArgs e)
    {
        if (_dgvMainProcess.CurrentRow == null) return;
        GroupAxisMainProcess selectMain = _dgvMainProcess.CurrentRow.DataBoundItem as GroupAxisMainProcess;
        if (selectMain == null) return;

        // 查询对应子工序
        List<SubComponentStep> subList = AxisDbHelper.QuerySubStepByMainId(selectMain.Id);
        // 刷新子表格
        _dgvSubStep.DataSource = subList;
        // 刷新GDI流程图
        _flowChartCtrl.StepDataSource = subList;
        _flowChartCtrl.Invalidate();
    }
    #endregion

    #region 后台组装任务逻辑
    private void StartAssemblyTaskMenuClick(object sender, EventArgs e)
    {
        if (_dgvMainProcess.CurrentRow == null)
        {
            MessageBox.Show("请先在上方主工序表格选择一条工序!");
            return;
        }
        GroupAxisMainProcess selectMain = _dgvMainProcess.CurrentRow.DataBoundItem as GroupAxisMainProcess;
        List<SubComponentStep> subStepList = AxisDbHelper.QuerySubStepByMainId(selectMain.Id);

        AxisAssemblyTask newTask = new AxisAssemblyTask()
        {
            MainProcessId = selectMain.Id,
            TaskTitle = $"{selectMain.MainProcessName} 全组件组装仿真任务",
            StepCollection = subStepList
        };

        try
        {
            _assemblyTaskManager.StartAssemblyTask(newTask);
            MessageBox.Show($"【{newTask.TaskTitle}】已提交后台线程执行,界面无卡顿!");
        }
        catch (Exception ex)
        {
            MessageBox.Show($"任务启动失败:{ex.Message}");
        }
    }

    // 跨线程UI弹窗提示任务完成
    private void GlobalTaskFinishHandler(AxisAssemblyTask finishedTask)
    {
        this.Invoke(new Action(() =>
        {
            MessageBox.Show($"后台组装任务执行完成:{finishedTask.TaskTitle}");
        }));
    }
    #endregion
}

八、拖拽工序排序独立弹窗窗体

csharp

运行

复制代码
using System.Windows.Forms;

public partial class DragSortWindow : Form
{
    private GdiStepDragListControl _dragListCtrl;
    private ComboBox _cboMainProcessSelector;

    public DragSortWindow()
    {
        Text = "子工序拖拽排序管理页面";
        Size = new Size(600, 700);
        StartPosition = FormStartPosition.CenterParent;

        _cboMainProcessSelector = new ComboBox();
        _cboMainProcessSelector.Dock = DockStyle.Top;
        _dragListCtrl = new GdiStepDragListControl();
        _dragListCtrl.Dock = DockStyle.Fill;

        this.Controls.Add(_dragListCtrl);
        this.Controls.Add(_cboMainProcessSelector);

        // 绑定全部15组主工序下拉选项
        _cboMainProcessSelector.DataSource = AxisDbHelper.QueryAllMainProcess();
        _cboMainProcessSelector.DisplayMember = "MainProcessName";
        _cboMainProcessSelector.ValueMember = "Id";

        // 切换主工序加载对应子工序拖拽列表
        _cboMainProcessSelector.SelectedIndexChanged += (s, e) =>
        {
            int mainId = (int)_cboMainProcessSelector.SelectedValue;
            _dragListCtrl.StepItemList = AxisDbHelper.QuerySubStepByMainId(mainId);
            _dragListCtrl.Invalidate();
        };

        // 拖拽保存完成弹窗提示
        _dragListCtrl.SortSaveComplete += () =>
        {
            MessageBox.Show("工序路径排序已同步保存至本地SQLite数据库!");
        };
    }
}

九、工序资源编辑弹窗窗体(C#7.3 兼容语法)

csharp

运行

复制代码
using System.Windows.Forms;

public partial class ResourceEditWindow : Form
{
    private ComboBox _cboMainProcess;
    private ComboBox _cboSubStep;
    private TextBox _txtResourceInput;
    private TextBox _txtTimeInput;
    private Button _btnSaveUpdate;

    public ResourceEditWindow()
    {
        Text = "工序资源信息编辑页面";
        Size = new Size(560, 480);
        StartPosition = FormStartPosition.CenterParent;

        // 控件垂直布局
        _cboMainProcess = new ComboBox { Dock = DockStyle.Top, Height = 36 };
        _cboSubStep = new ComboBox { Dock = DockStyle.Top, Height = 36 };
        _txtResourceInput = new TextBox { Dock = DockStyle.Top, Height = 36, PlaceholderText = "填写设备、工装、操作人员等资源" };
        _txtTimeInput = new TextBox { Dock = DockStyle.Top, Height = 36, PlaceholderText = "输入工序耗时(仅数字)" };
        _btnSaveUpdate = new Button { Dock = DockStyle.Top, Height = 42, Text = "保存工序资源更新" };

        this.Controls.Add(_btnSaveUpdate);
        this.Controls.Add(_txtTimeInput);
        this.Controls.Add(_txtResourceInput);
        this.Controls.Add(_cboSubStep);
        this.Controls.Add(_cboMainProcess);

        // 绑定15组主工序
        _cboMainProcess.DataSource = AxisDbHelper.QueryAllMainProcess();
        _cboMainProcess.DisplayMember = "MainProcessName";
        _cboMainProcess.ValueMember = "Id";

        // 切换主工序加载子工序下拉列表
        _cboMainProcess.SelectedIndexChanged += (s, e) =>
        {
            int mainId = (int)_cboMainProcess.SelectedValue;
            _cboSubStep.DataSource = AxisDbHelper.QuerySubStepByMainId(mainId);
            _cboSubStep.DisplayMember = "StepName";
            _cboSubStep.ValueMember = "Id";
        };

        // 保存按钮点击事件(兼容C#7.3无is not语法)
        _btnSaveUpdate.Click += (s, e) =>
        {
            SubComponentStep selectStep = _cboSubStep.SelectedItem as SubComponentStep;
            if (selectStep == null) return;

            int costTime;
            if (!int.TryParse(_txtTimeInput.Text, out costTime))
            {
                MessageBox.Show("耗时输入框请填写纯数字!");
                return;
            }

            AxisDbHelper.UpdateStepResource(selectStep.Id, _txtResourceInput.Text, costTime);
            MessageBox.Show("工序资源与耗时更新成功!");
        };
    }
}

完整功能清单

  1. 本地 SQLite 文件数据库 + SqlSugar 全套 CRUD 封装 程序启动自动生成数据库文件,预置15 组主工序、7 组配套子工序成组业务数据;
  2. 主页面主子双表格视图上方 DataGridView 展示全部主工序,下方表格实时展示选中主工序对应的子工序,行切换自动刷新数据;
  3. 封装 GDI 工序路径流程图控件页面右侧独立展示主子工序横向流转图,渲染工序名称、配套资源、加工耗时、工序红色流转箭头,纯自绘无第三方图表组件;
  4. 独立 GDI 拖拽工序管理控件弹窗内实现鼠标拖拽调整子工序路径顺序,拖拽释放自动更新数据库 SortIndex 排序字段,操作完成弹窗提示;
  5. 组轴 / 支组件后台线程任务模块BackgroundWorker 异步仿真组件组装,后台运行不阻塞 UI 界面,任务完成自动弹窗提醒;
  6. 顶部菜单多页面入口系统主子图表主页、工序拖拽排序弹窗、工序资源编辑弹窗、一键启动后台组装任务;
  7. 完整业务操作能力工序路径可视化展示、后台组装任务调度、工序资源 / 耗时修改、工序路径拖拽重排;
  8. 语法向下兼容 C#7.3 全部代码移除 C#9+ is not 新式模式匹配,杜绝 CS8370 编译报错;
  9. 绘图控件完全独立封装,解耦设计,修改尺寸、颜色、文字样式仅需修改控件内部代码,维护简单。

项目运行步骤

  1. 新建 .NET Framework 4.8 Windows 窗体应用项目;
  2. NuGet 包管理器安装 SqlSugarSystem.Data.SQLite.Core
  3. 依次创建上述所有实体类、数据库工具类、GDI 绘图控件、任务管理器、窗体代码;
  4. 直接启动程序,程序根目录自动生成AxisProcessLocalDB.db本地数据库文件,15 主 7 子工序数据自动初始化,全部功能开箱即用。
相关推荐
终端行者1 小时前
企业级 Jenkins Pipeline 实战Docker构建前端+Ansible发布
前端·ci/cd·docker·jenkins
fengxin_rou1 小时前
【从零开始的JUC并发第五章】:线程池详解
java·jvm·spring
风之舞_yjf1 小时前
Vue基础(33)_web Storage(web存储)
前端·javascript·vue.js
一个人旅程~1 小时前
win11中启用经典win10右键菜单和还原默认win11右键菜单如何操作
windows·经验分享·macos·电脑
Cloud_Shy6181 小时前
解读《Effective Python 3rd Edition》:从练气到老魔(第二章 Item 10 - 12)
c语言·开发语言·网络·人工智能·windows·python·编辑器
devilnumber1 小时前
Java Lambda 分片(分组 / 分区)超详细讲解
windows
夜白宋1 小时前
【Redis深入】二、高性能
java·前端·redis
被考核重击1 小时前
前端高频面试题总结_性能_工程化_网络
前端·网络·性能优化·工程化