开发一个主页面包含主子节点表格的工序路径的图表控件的页面,工序管理操作界面带拖拽式控件,组支轴事件任务线程执行层面,事件组轴和线程支组件组装工序路径资源功能模块,相关菜单页面SqlSugar函数方法预备7,15组工序成组数据,项目主要使用GDI绘图绘制,界面的图表控件尽量封装实现,实现本地文件化数据库的Winform端的代码实现组件
WinForm 组支轴主子节点工序管理完整工程
项目整体说明
核心技术栈
WinForm (.NET Framework4.8) + SqlSugar + SQLite 本地文件数据库 + GDI + 独立封装图表控件 + BackgroundWorker 后台任务线程
业务需求落地
- 预置15 组主工序、7 组配套子工序成组业务数据;
- 主页面双视图:主子节点 DataGridView 表格 + GDI 工序路径流程图控件;
- 独立拖拽工序管理窗体,GDI 自绘拖拽列表,拖拽调整工序路径顺序,自动入库;
- 后台线程任务模块:异步执行组轴 / 支组件组装仿真,全程不阻塞 UI;
- 顶部菜单栏多页面入口:图表主页、拖拽管理、工序资源编辑、启动组装任务;
- 全代码兼容 C#7.3,移除
is not等高版本语法,杜绝 CS8370 编译报错; - 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("工序资源与耗时更新成功!");
};
}
}
完整功能清单
- 本地 SQLite 文件数据库 + SqlSugar 全套 CRUD 封装 程序启动自动生成数据库文件,预置15 组主工序、7 组配套子工序成组业务数据;
- 主页面主子双表格视图上方 DataGridView 展示全部主工序,下方表格实时展示选中主工序对应的子工序,行切换自动刷新数据;
- 封装 GDI 工序路径流程图控件页面右侧独立展示主子工序横向流转图,渲染工序名称、配套资源、加工耗时、工序红色流转箭头,纯自绘无第三方图表组件;
- 独立 GDI 拖拽工序管理控件弹窗内实现鼠标拖拽调整子工序路径顺序,拖拽释放自动更新数据库 SortIndex 排序字段,操作完成弹窗提示;
- 组轴 / 支组件后台线程任务模块BackgroundWorker 异步仿真组件组装,后台运行不阻塞 UI 界面,任务完成自动弹窗提醒;
- 顶部菜单多页面入口系统主子图表主页、工序拖拽排序弹窗、工序资源编辑弹窗、一键启动后台组装任务;
- 完整业务操作能力工序路径可视化展示、后台组装任务调度、工序资源 / 耗时修改、工序路径拖拽重排;
- 语法向下兼容 C#7.3 全部代码移除 C#9+
is not新式模式匹配,杜绝 CS8370 编译报错; - 绘图控件完全独立封装,解耦设计,修改尺寸、颜色、文字样式仅需修改控件内部代码,维护简单。
项目运行步骤
- 新建 .NET Framework 4.8 Windows 窗体应用项目;
- NuGet 包管理器安装
SqlSugar、System.Data.SQLite.Core; - 依次创建上述所有实体类、数据库工具类、GDI 绘图控件、任务管理器、窗体代码;
- 直接启动程序,程序根目录自动生成
AxisProcessLocalDB.db本地数据库文件,15 主 7 子工序数据自动初始化,全部功能开箱即用。