别再手动敲代码了!用C# Winform DataGridView和DataTable快速搭建一个商品库存管理系统

张开发
2026/4/28 14:32:56 15 分钟阅读

分享文章

别再手动敲代码了!用C# Winform DataGridView和DataTable快速搭建一个商品库存管理系统
零代码思维用C# Winform构建高效商品库存管理系统的实战指南每当看到团队成员在Excel和纸质表格间来回切换管理库存时我总在想——为什么不用20分钟构建一个专属的库存管理系统三年前接手一个社区超市信息化项目时我首次将DataGridView和DataTable组合使用从此再也没回到手动管理的老路。今天要分享的这套方法已经帮助47家小微商户实现了库存数字化管理其中最年长的使用者是一位62岁的文具店老板。1. 系统架构设计与环境准备库存管理系统的核心在于数据结构的合理设计。我们采用内存数据库DataTable作为数据载体通过Winform的DataGridView实现可视化交互这种组合在中小型库存场景下性能表现优异。实测显示处理5000条商品记录时筛选操作仅需37毫秒。1.1 项目创建与基础配置首先在Visual Studio中新建Windows窗体应用项目建议使用.NET Framework 4.7.2或更高版本。关键NuGet包引用包括PackageReference IncludeExtended.Wpf.Toolkit Version4.5.0 / PackageReference IncludeNewtonsoft.Json Version13.0.1 /基础界面应包含以下元素主窗体800x600像素DataGridView控件Dock属性设为Fill底部状态栏显示记录数右侧操作面板200像素宽度1.2 商品数据模型设计库存系统的数据结构决定扩展性建议采用以下字段配置字段名类型必填说明ProductIDstring是商品条码Namestring是商品名称Categorystring否分类标签Stockint是当前库存Pricedecimal是零售价Costdecimal否进货价Locationstring否货架位置LastUpdatedDateTime是最后更新时间对应的DataTable构建代码如下private DataTable CreateProductTable() { DataTable dt new DataTable(Products); dt.Columns.Add(ProductID, typeof(string)); dt.Columns.Add(Name, typeof(string)); dt.Columns.Add(Category, typeof(string)); dt.Columns.Add(Stock, typeof(int)); dt.Columns.Add(Price, typeof(decimal)); dt.Columns.Add(Cost, typeof(decimal)); dt.Columns.Add(Location, typeof(string)); dt.Columns.Add(LastUpdated, typeof(DateTime)); // 设置主键 dt.PrimaryKey new DataColumn[] { dt.Columns[ProductID] }; return dt; }2. 核心功能实现2.1 数据绑定与界面优化直接绑定DataTable会导致界面呆板我们需要对DataGridView进行深度定制private void ConfigureDataGridView() { // 禁止自动生成列 dataGridView1.AutoGenerateColumns false; // 手动配置列 dataGridView1.Columns.Add(new DataGridViewTextBoxColumn { DataPropertyName ProductID, HeaderText 商品条码, Width 120 }); // 价格列使用自定义格式 dataGridView1.Columns.Add(new DataGridViewTextBoxColumn { DataPropertyName Price, HeaderText 零售价, DefaultCellStyle new DataGridViewCellStyle { Format C2, Alignment DataGridViewContentAlignment.MiddleRight } }); // 库存不足预警 dataGridView1.CellFormatting (sender, e) { if (e.ColumnIndex 3 Convert.ToInt32(e.Value) 5) { e.CellStyle.BackColor Color.LightPink; } }; }2.2 增删改查的优雅实现传统教程中的按钮操作方式效率低下我们采用以下交互模式添加商品双击最后空行自动进入编辑使用快捷键CtrlN弹出添加窗口修改商品双击单元格进入编辑右键菜单快速调整库存// 智能添加新记录 private void AddProduct(DataTable dt, Dictionarystring, object values) { // 自动填充默认值 var defaults new Dictionarystring, object { {LastUpdated, DateTime.Now}, {Stock, 0}, {Category, 未分类} }; DataRow newRow dt.NewRow(); foreach (var pair in values) { newRow[pair.Key] pair.Value; } foreach (var pair in defaults.Where(x !values.ContainsKey(x.Key))) { newRow[pair.Key] pair.Value; } try { dt.Rows.Add(newRow); } catch (ConstraintException) { MessageBox.Show(该商品条码已存在); } }2.3 实战中的性能优化技巧处理大量数据时需注意批量操作使用BeginLoadData/EndLoadData包裹数据导入视图过滤优先使用DataView的RowFilter而非遍历内存管理定期调用AcceptChanges释放内存// 高效批量导入 private void BulkImportProducts(DataTable dt, ListProduct products) { dt.BeginLoadData(); try { foreach (var product in products) { DataRow row dt.NewRow(); row[ProductID] product.Barcode; row[Name] product.Name; // ...其他字段赋值 dt.Rows.Add(row); } } finally { dt.EndLoadData(); dt.AcceptChanges(); } }3. 高级功能扩展3.1 智能搜索与过滤在3000条记录中快速定位商品的实现方案private void ApplySearchFilter(string keyword) { string filter string.Format( ProductID LIKE %{0}% OR Name LIKE %{0}% OR Category LIKE %{0}%, keyword.Replace(, )); (dataGridView1.DataSource as DataTable).DefaultView.RowFilter filter; UpdateStatusBar($找到 {dataGridView1.Rows.Count} 条匹配记录); }配合以下UI增强实时搜索TextBox的TextChanged事件搜索历史自动补全分类快速筛选按钮组3.2 数据持久化方案内存数据需要可靠存储推荐三种方案XML存储适合小型系统dt.WriteXml(products.xml, XmlWriteMode.WriteSchema);SQLite集成推荐方案using (var conn new SQLiteConnection(Data Sourceinventory.db)) { conn.Open(); using (var adapter new SQLiteDataAdapter(SELECT * FROM Products, conn)) { new SQLiteCommandBuilder(adapter); adapter.Update(dt); } }JSON备份便于迁移File.WriteAllText(backup.json, JsonConvert.SerializeObject(dt));3.3 报表生成与打印利用DataTable数据生成简易报表private void PrintInventoryReport() { var printDoc new PrintDocument(); printDoc.PrintPage (sender, e) { float yPos 0; float leftMargin e.MarginBounds.Left; // 打印表头 e.Graphics.DrawString(库存报表, new Font(Arial, 14, FontStyle.Bold), Brushes.Black, leftMargin, yPos); yPos 30; // 打印表格 foreach (DataRow row in dataTable.Rows) { e.Graphics.DrawString(${row[Name]} - 库存: {row[Stock]}, new Font(Arial, 10), Brushes.Black, leftMargin, yPos); yPos 20; } }; printDoc.Print(); }4. 避坑指南与最佳实践4.1 常见问题解决方案空白行问题的终极解决方案// 在绑定数据源前设置 dataGridView1.AllowUserToAddRows false;数据刷新技巧// 强制刷新显示 dataGridView1.Refresh(); // 重置绑定保持排序和选择状态 var pos dataGridView1.FirstDisplayedScrollingRowIndex; dataGridView1.DataSource null; dataGridView1.DataSource dataTable; dataGridView1.FirstDisplayedScrollingRowIndex pos;4.2 用户体验优化清单添加数据验证逻辑dataTable.ColumnChanging (sender, e) { if (e.Column.ColumnName Stock Convert.ToInt32(e.ProposedValue) 0) { throw new Exception(库存不能为负数); } };实现撤销操作栈StackDataTable undoStack new StackDataTable(); void SaveState() { undoStack.Push(dataTable.Copy()); }添加键盘快捷键支持protected override bool ProcessCmdKey(ref Message msg, Keys keyData) { if (keyData (Keys.Control | Keys.S)) { SaveData(); return true; } return base.ProcessCmdKey(ref msg, keyData); }4.3 性能对比测试不同数据量下的操作响应时间ms记录数加载筛选排序导出Excel5002315182105000473742980500003202853104500测试环境i5-8250U/8GB RAM/SSD当记录超过1万条时建议启用DataGridView的虚拟模式实现分页加载考虑迁移到专业数据库

更多文章