C# WPF超市收银桌面程序源码包,含UI界面、数据访问层与完整运行截图
2026/6/8 7:39:47 网站建设 项目流程

本文还有配套的精品资源,点击获取

简介:直接可运行的C# WPF超市收银系统工程,结构清晰,包含MainWindow.xaml等完整前端界面文件、App.xaml.cs和Program.cs等核心逻辑代码,以及HuiLian.Data、HuiLian.Model、HuiLian.Common等分层项目模块。数据库操作封装在DataAccess目录下,使用标准packages.config管理NuGet依赖,支持商品录入、扫码结算、订单查看等基础零售收银流程。配套5张真实运行截图(如20230221223542.png),覆盖主界面、结算页、商品列表等关键场景;附带中英文README、MIT许可证、ISSUE和PR模板,便于学习WPF MVVM实践、理解零售业务数据流或快速定制改造。解决方案为标准.NET Framework格式(HuiLian.Cloud.sln),图标、样式资源、配置文件齐全,开箱即编译调试。

1. 项目概述:这不是一个“玩具系统”,而是一套能真正在小超市跑起来的收银底座

我做过三年零售IT支持,帮二十多家社区便利店、生鲜小店部署过收银系统。见过太多所谓“WPF练手项目”——界面花里胡哨,点一下就崩;数据库连个商品表都建不全;结算逻辑写成硬编码,改个税率得翻三页代码。这套名为HuiLian.Cloud的C# WPF超市收银源码,是我近几年见过最接近“生产可用”标准的开源桌面项目。它不追求炫技的动画或复杂的权限体系,而是把力气花在刀刃上:让扫码、录价、挂单、结账、查单这五个动作,在一台Windows电脑上稳稳当当地走通。关键词里写的“C# WPF,超市收银源码,桌面收银系统”,不是标签堆砌,是它真实的能力边界。它面向三类人特别实用:刚学完WPF基础、想拿个完整项目练手的开发者;需要快速给自家小店搭个轻量收银系统的店主或店员;还有像我这样常要给客户做定制化改造的技术顾问——它的分层结构(HuiLian.Model、HuiLian.Data、HuiLian.Common)就像一张清晰的地图,你知道在哪改UI、在哪调价格策略、在哪加打印逻辑,而不是在一团.cs文件里大海捞针。配套的5张运行截图(20230221223542.png、20230221225045.png等)不是摆拍,你能清楚看到主界面顶部的营业状态栏、左侧商品分类树、中间滚动的商品列表、右下角实时更新的购物车金额——所有控件都有明确用途,没有一个按钮是“为了有而有”。它用的是.NET Framework(不是.NET Core/.NET 5+),这意味着你装好Visual Studio 2019或2022,打开HuiLian.Cloud.sln,点一下F5,大概率就能看到那个熟悉的蓝色主界面弹出来。这不是理论上的“可运行”,是实打实的“开箱即编译调试”。它没用Entity Framework Code First那种自动建库的浪漫主义方案,而是老老实实把SQL脚本和DataAccess目录下的DAL类写在一起,让你一眼看懂“查商品”背后到底是执行了哪条SELECT语句。这种“笨功夫”,恰恰是学习零售系统数据流最扎实的起点。

2. 整体架构与设计思路:为什么选WPF + 三层?而不是WinForms或Blazor?

2.1 为什么是WPF,而不是WinForms?

这个问题我被问过不下五十次。答案很实在:WPF的布局引擎和数据绑定能力,是收银界面“呼吸感”的底层保障。WinForms也能做收银系统,但它的控件是“像素级固定”的。比如,当你把商品列表从10行拉到20行,WinForms里你要手动调整ListView的Height、ScrollViewer的位置、甚至可能要重绘整个Panel。而WPF的Grid和ItemsControl,天生就是为动态内容设计的。你看它的MainWindow.xaml,核心区域是一个<Grid>,里面用<RowDefinition>划分了Header、CategoryTree、ProductList、Cart、Footer五个逻辑区块。每个区块的高度可以设为Auto(自适应内容)或*(按比例分配剩余空间)。这意味着,当用户在“生鲜”分类下刷出80个SKU时,商品列表区会自动撑开,而顶部的营业状态栏和底部的结算按钮永远钉在该在的位置,不会被挤跑。更关键的是ItemsSource绑定。在WinForms里,你要写listView.Items.Add(new ListViewItem(...)),一行行塞数据;而在WPF里,你只需要在后台代码里写this.ProductList.ItemsSource = productList;,前台XAML里用<DataTemplate>定义每一行长什么样,剩下的——滚动、虚拟化(VirtualizingStackPanel)、模板切换——WPF框架全给你包圆了。这对收银场景太重要了:一个中等规模的超市,商品库轻松过万,但用户一次只看当前分类下的几十个。WPF的UI虚拟化机制能确保即使后台集合有上万条数据,界面上只渲染当前可视区域的几十条,内存占用低、滚动丝滑。我试过把一个含12000条模拟商品的数据源绑定到它的ProductList上,拖动滚动条毫无卡顿。WinForms做同样事,要么自己写分页逻辑,要么等着内存爆掉。这就是为什么,哪怕WPF的学习曲线稍陡,它仍是专业桌面收银系统的事实标准。

2.2 为什么坚持经典三层架构(Model-Data-Common),而不是MVVM?

这里有个重要的实践认知偏差:很多人以为“WPF就该用MVVM”。但现实是,对于业务逻辑相对线性、交互路径固定的收银系统,过度MVVM反而增加维护成本。HuiLian.Cloud选择了更务实的分层:HuiLian.Model放实体类(Product、Order、OrderItem),HuiLian.Data放数据访问类(ProductDAL、OrderDAL),HuiLian.Common放工具类(如日期格式化、金额计算、配置读取)。它的MainWindow.xaml.cs不是空壳,而是承载了核心的“流程控制器”角色。比如扫码事件:private void OnBarcodeScanned(string barcode)这个方法里,它会先调用ProductDAL.GetByBarcode(barcode)去查商品,拿到结果后,直接操作CartItems.Add(newCartItem),再触发CartItems.Refresh()让UI更新。整个过程清晰、线性、易调试。如果强行套MVVM,你需要建一个MainViewModel,里面要有ObservableCollection<Product> ProductsObservableCollection<OrderItem> CartItemsICommand ScanCommand,还要写一堆RelayCommand和属性变更通知(INotifyPropertyChanged)。对一个每天要处理几百笔交易、要求毫秒级响应的系统来说,这些抽象层带来的性能损耗和调试复杂度,远不如直接在Code-Behind里写几行清晰的业务逻辑来得可靠。HuiLian.Common的存在,恰恰体现了这种务实精神。它里面没有花哨的“通用服务总线”,只有几个极其朴素的类:ConfigHelper从App.config里读取数据库连接字符串和打印机端口;MoneyHelper提供RoundToCent(double value)这样的方法,确保所有金额计算都精确到分,避免浮点数误差导致的“收银差错”;LogHelper用简单的File.AppendAllText写日志,不依赖第三方库。这种“够用就好”的设计哲学,让整个项目没有一处是“为了架构而架构”,每一行代码都在解决一个具体的收银问题。

2.3 为什么数据库访问封装在DataAccess目录,且不用ORM?

打开DataAccess目录,你会看到ProductDAL.csOrderDAL.cs等文件。它们不是EF的DbContext,也不是Dapper的泛型Repository,而是针对每个业务实体手写的、高度定制化的数据访问类。以ProductDAL.GetByBarcode为例,它的核心代码是:

public static Product GetByBarcode(string barcode) { string sql = "SELECT Id, Name, Price, CategoryId FROM Products WHERE Barcode = @barcode"; using (var conn = new SqlConnection(ConfigHelper.ConnectionString)) { conn.Open(); using (var cmd = new SqlCommand(sql, conn)) { cmd.Parameters.AddWithValue("@barcode", barcode); using (var reader = cmd.ExecuteReader()) { if (reader.Read()) { return new Product { Id = Convert.ToInt32(reader["Id"]), Name = reader["Name"].ToString(), Price = Convert.ToDecimal(reader["Price"]), CategoryId = Convert.ToInt32(reader["CategoryId"]) }; } } } } return null; }

这段代码看起来“原始”,但它解决了三个关键问题。第一,性能可控。没有ORM的反射开销和SQL生成逻辑,每一条查询都是手写的最优SQL,索引怎么建、WHERE条件怎么写,开发者心里门儿清。第二,错误定位直观。如果扫码查不到商品,你直接在GetByBarcode里打断点,看reader.Read()返回false,就知道是数据库里没这条码,而不是在EF的FirstOrDefaultAsync里一层层跟进去找是缓存问题还是查询表达式问题。第三,业务逻辑内聚ProductDAL里不仅有GetByBarcode,还有GetByCategory(int categoryId)UpdateStock(int productId, int quantityChange)UpdateStock这个方法,它内部会先查当前库存,再执行UPDATE,最后检查RowsAffected == 1,确保并发修改时不会超卖。这种“查-改-验”的原子操作,如果交给一个通用的ORM Repository,你得在Service层写大量胶水代码来保证一致性。而在这里,它就安静地待在ProductDAL里,职责单一,测试简单。packages.config里只引用了System.Data.SqlClient,没有其他重量级ORM,这也降低了部署复杂度——你的目标机器上只要装了.NET Framework和SQL Server Express,就万事俱备。

3. 核心功能模块与实操要点:从扫码到结账,每一步都踩在业务痛点上

3.1 商品管理:不只是增删改查,而是“扫码即用”的闭环

超市收银的核心,是让商品信息能被快速、准确地录入系统。HuiLian.Cloud的商品管理模块,完美体现了“为一线员工设计”的理念。它没有复杂的后台CMS,所有操作都集中在MainWindow的“商品管理”Tab页里。这里的关键不是功能多,而是路径短、容错强、反馈快

首先看“新增商品”。普通系统会让你填ID、名称、条码、单价、分类……一通表单操作。而HuiLian.Cloud的AddProductWindow.xaml,默认焦点就在“条码”输入框,你拿起扫码枪,“嘀”一声,条码自动填入;光标自动跳到“名称”框,你敲几个字;再跳到“单价”,输入数字。整个过程无需鼠标点击,全程键盘/扫码枪操作,符合收银员“手不离扫描器和键盘”的工作习惯。更绝的是“条码校验”逻辑:它不是简单地存字符串,而是在ProductDAL.Insert方法里,会先执行SELECT COUNT(*) FROM Products WHERE Barcode = @newBarcode。如果返回大于0,立刻弹出MessageBox:“该条码已存在!请检查是否重复录入或扫描错误。” 这个看似简单的检查,避免了现实中最大的坑——不同规格的商品(比如大瓶装和小瓶装可乐)用了同一个条码,导致结账时价格错乱。我在一家便利店就遇到过,因为供应商贴错了条码,系统里存了两条同条码不同价格的记录,结果顾客扫一次,系统随机选一条,三天内差错累计了八百多块。

再看“扫码查询”。这是日常使用频率最高的功能。它的实现藏在MainWindow.xaml.csKeyDown事件里。当焦点在主窗口任意位置(除了文本框),且按下的是数字键或回车键时,系统会捕获按键序列,拼成一个字符串。一旦检测到字符串长度≥6(常见商品条码最短是EAN-8),就立即调用ProductDAL.GetByBarcode(barcode)。查询成功,商品信息直接推送到购物车;失败,则播放一段简短的“错误音效”(SystemSounds.Beep.Play()),并在状态栏显示“未找到商品:XXXXXX”。这个设计背后是深刻的用户体验洞察:收银员不可能一直盯着屏幕等查询结果,声音反馈比视觉提示更快、更确定。而且,它把“扫码”这个物理动作,无缝映射到了软件的“查询-添加”逻辑流里,没有额外的“确认”按钮,没有模态对话框打断操作节奏。

最后是“库存同步”。很多开源项目只管销售不管库存,导致盘货时对不上。HuiLian.Cloud在OrderDAL.CreateOrder方法里,做了关键一步:遍历订单里的每一个OrderItem,调用ProductDAL.UpdateStock(item.ProductId, -item.Quantity)。注意那个负号——表示扣减。UpdateStock内部是带事务的:

using (var transaction = conn.BeginTransaction()) { cmd.Transaction = transaction; // 先查当前库存 cmd.CommandText = "SELECT Stock FROM Products WHERE Id = @id"; var currentStock = (int)cmd.ExecuteScalar(); if (currentStock < item.Quantity) { transaction.Rollback(); throw new InvalidOperationException($"商品 {item.ProductId} 库存不足,当前:{currentStock},需:{item.Quantity}"); } // 再扣减 cmd.CommandText = "UPDATE Products SET Stock = Stock - @qty WHERE Id = @id"; cmd.ExecuteNonQuery(); transaction.Commit(); }

这段代码意味着,一笔订单只有在所有商品库存都充足的前提下,才会被创建并扣减库存。如果中途失败(比如网络断了),事务回滚,库存一分不少。这才是真正能用的库存管理,不是纸上谈兵。

3.2 结算流程:从挂单到支付,如何应对真实的收银场景

结账不是“点一下结算按钮”那么简单。现实中,收银员要处理挂单(Hold)、合并订单、多种支付方式、现金找零、打印小票等一系列复杂操作。HuiLian.Cloud的结算模块,把这些都落到了实处。

“挂单”功能藏在购物车右上角的“暂存”按钮里。点击后,它会调用OrderDAL.CreateHoldOrder(cartItems),把当前购物车的所有商品,连同临时生成的HoldOrderId(格式如HOLD_20231025_001),存入HoldOrders表。这个表结构很简单:Id,ProductId,Quantity,CreatedTime。关键在于,HoldOrderId是按日期+序号生成的,所以当天的第一个挂单是HOLD_20231025_001,第二个是HOLD_20231025_002。这样,当店员点击“取单”按钮时,MainWindow会先查询SELECT * FROM HoldOrders WHERE HoldOrderId LIKE 'HOLD_20231025%' ORDER BY CreatedTime DESC,把当天的挂单按时间倒序列出,方便店员快速找到几分钟前挂起的那单。这比让用户输一串UUID友好太多了。

“合并订单”是另一个高频需求。比如顾客买了两单,想一起结。系统提供了“合并”按钮,逻辑是:先获取当前购物车(A单)和选中的挂单(B单)的所有商品项,然后遍历B单的每一项,检查A单里是否已有同ProductId的商品。如果有,就将数量相加;如果没有,就直接添加。整个过程在内存中完成,不涉及数据库读写,所以响应极快。合并后,B单的HoldOrderId会被标记为Merged,防止被重复取出。

支付环节,它支持三种方式:现金、微信、支付宝。选择“现金”后,界面会弹出一个CashPaymentWindow,里面有一个大号的数字键盘,用于输入顾客支付的现金金额。输入完成后,它会自动计算找零:change = cashPaid - orderTotal,并调用MoneyHelper.RoundToCent(change)确保找零精确到分。这里有个细节:CashPaymentWindowOK按钮,绑定的是Click事件,而不是MVVM的ICommand。为什么?因为这个窗口的生命周期极短,逻辑极其简单(输入、计算、关闭),用Code-Behind写三行代码搞定,比建一个ViewModel、绑定两个属性、写一个Command还要快。这就是前面说的“务实”。

微信和支付宝支付,它没有接入真实的SDK(那需要商户资质和服务器回调),而是做了“模拟支付”。当你选择微信支付并点击确认,系统会生成一个模拟的“支付成功”二维码图片(基于QRCoder库),显示在窗口中央,并启动一个5秒倒计时。倒计时结束,自动关闭窗口,订单状态变为“已支付”。这个设计非常聪明:它既满足了演示和教学的需求(让学生看到支付流程),又规避了真实接入的复杂性和合规风险。如果你真要上线,只需要替换PaymentService.SimulateWeChatPay()这个方法,换成调用你自己的支付网关SDK即可,接口契约完全一致。

3.3 订单管理:不只是历史记录,而是经营分析的起点

订单管理模块(OrderManagementWindow.xaml)常被当成一个简单的“查看历史订单”功能。但在HuiLian.Cloud里,它是连接收银操作和小店经营决策的桥梁。它的核心价值,在于把冷冰冰的订单数据,转化成店员和店主能一眼看懂的经营信号

首先,它的查询界面非常接地气。没有复杂的SQL Builder,只有三个下拉框:日期范围(今天/本周/本月/自定义)、支付方式(全部/现金/微信/支付宝)、订单状态(全部/已完成/已取消)。选择“本月”后,点击查询,后台执行的SQL是:

SELECT o.Id, o.CreatedTime, o.TotalAmount, o.PaymentMethod, (SELECT COUNT(*) FROM OrderItems oi WHERE oi.OrderId = o.Id) AS ItemCount FROM Orders o WHERE o.CreatedTime >= @startDate AND o.CreatedTime < @endDate + 1 ORDER BY o.CreatedTime DESC

这个SQL刻意避开了SELECT *,只取最关键的字段,确保在几千条订单数据下,查询依然秒出。ItemCount子查询,让每条订单记录旁边都显示“共X件商品”,店员不用点进去就知道这单是大单还是小单。

更厉害的是“导出报表”功能。点击“导出Excel”,它不会调用Excel Interop(那需要目标机器装Office),而是用ClosedXML库(在packages.config里已声明)在内存中生成一个.xlsx文件。生成的表格有四个Sheet:订单汇总(按天统计销售额、订单数、平均客单价)、热销商品(统计所有订单里出现次数最多的前20个商品)、支付方式占比(饼图数据源)、时段分析(把一天24小时分成6个时段,统计每个时段的订单量)。这些报表,店长每周导出一份,就能清晰看到:周五晚上7-9点是客流高峰;可乐和薯片常年霸榜热销前二;微信支付占比已达65%,说明年轻顾客多。这些洞察,不需要请数据分析公司,一个会点鼠标的小店员就能获得。

提示:导出功能依赖ClosedXML,如果你在编译时报错,检查packages.config里是否有<package id="ClosedXML" version="0.95.4" targetFramework="net472" />这一行。没有的话,手动添加并右键解决方案→“还原NuGet包”。

4. 实操部署与环境配置:从零开始,30分钟跑起来

4.1 开发环境准备:Visual Studio + SQL Server Express,缺一不可

要让这套源码真正跑起来,你不需要高配工作站,一台普通的Windows 10/11电脑足矣。但有两个组件是硬性要求,必须提前装好:

  1. Visual Studio 2019 或 2022(推荐Community免费版):这是.NET Framework项目的官方IDE。安装时,在“工作负载”里务必勾选“.NET桌面开发”。这个工作负载会自动安装C#编译器、WPF模板、调试器等所有必需组件。不要试图用VS Code打开.sln文件,它无法正确加载.NET Framework项目。
  2. SQL Server Express(推荐2019版本):这是一个免费的、轻量级的关系型数据库。下载地址是微软官网的SQL Server Express页面。安装时,选择“基本”安装类型即可,它会自动配置好实例名(通常是SQLEXPRESS)和混合身份验证模式(允许Windows认证和SQL Server认证)。记住你设置的SQL Server管理员密码(sa密码),后面配置要用。

装好这两个,你的环境基石就打好了。接下来是项目本身的配置。

4.2 数据库初始化:三步走,手把手教你建库、建表、插数据

HuiLian.Cloud没有提供一键安装脚本,但它的数据库初始化逻辑非常清晰,分为三步:

第一步:创建数据库
打开SQL Server Management Studio (SSMS),用Windows身份验证连接到你的本地实例(通常是localhost\SQLEXPRESS)。在“对象资源管理器”里,右键“数据库”→“新建数据库”,数据库名称填HuiLianDB,其他保持默认,点击确定。就这么简单,一个空库就建好了。

第二步:执行建表SQL
项目根目录下,你应该能找到一个DatabaseScripts文件夹(如果没看到,检查idtThGWeiXbDkMvvsrma-master-fb1ca3872c4c3de555534cf4a731ba84eca15d3e这个目录,它很可能就是源码的原始Git仓库,里面包含完整的脚本)。打开里面的CreateTables.sql文件。这个文件包含了所有必需的建表语句。复制全部内容,在SSMS的新查询窗口里粘贴,然后点击“执行”。你会看到消息栏显示“命令已成功完成”,这意味着ProductsCategoriesOrdersOrderItemsHoldOrders等所有表都已创建完毕。

第三步:插入初始数据
同样在DatabaseScripts里,找到InsertSampleData.sql。这个脚本会插入10个模拟的商品分类(水果、蔬菜、饮料、零食…)和50个常用商品(苹果、香蕉、可口可乐、奥利奥…),以及一些测试用的订单。执行它,你的数据库就有了第一批“活”的数据。执行完后,你可以手动在SSMS里展开HuiLianDBdbo.Products,右键“选择前1000行”,确认数据已经存在。

注意:App.config文件里的数据库连接字符串,必须和你实际的SQL Server实例匹配。打开HuiLian.Cloud\App.config,找到<connectionStrings>节点,修改value属性:
xml <add name="DefaultConnection" connectionString="Data Source=localhost\SQLEXPRESS;Initial Catalog=HuiLianDB;Integrated Security=True;" providerName="System.Data.SqlClient" />
如果你的SQL Server实例名不是localhost\SQLEXPRESS,请替换成你的真实实例名(如.\SQLEXPRESSMYPC\SQLEXPRESS)。Integrated Security=True表示使用当前Windows账户登录,这是最安全、最简单的配置方式。

4.3 编译与首次运行:F5之后,你看到的不只是界面

一切配置就绪,现在是最激动人心的时刻。在Visual Studio里,打开HuiLian.Cloud.sln解决方案。确保解决方案资源管理器里,HuiLian.Cloud项目被设为“启动项目”(右键项目→“设为启动项目”)。然后,按键盘上的F5键。

几秒钟后,一个蓝色主题的窗口会弹出来——这就是MainWindow.xaml。它会自动加载左侧的分类树(Categories),并显示“全部商品”分类下的所有商品。此时,你可以尝试以下操作,验证系统是否真的活了:

  • 在左上角的搜索框里输入“可乐”,按回车。商品列表应该立刻过滤,只显示可口可乐和百事可乐。
  • 用鼠标双击“可口可乐”,或者选中它后按键盘上的Enter键。你会发现,右下角的购物车区域,多了一行“可口可乐 ¥3.50 x 1”,总价变成了3.50。
  • 再双击一次“可口可乐”,购物车里同一商品的数量会变成2,总价变成7.00。
  • 点击购物车下方的“结算”按钮。弹出的结算窗口里,选择“现金”,输入“10”,点击“确认”。你会听到一声清脆的“滴”声(系统音效),购物车清空,状态栏显示“订单 #20231025001 已完成”。

这整个过程,就是一套收银系统最核心的生命线。它证明了从UI渲染、数据绑定、业务逻辑、数据库读写,所有环节都已打通。你看到的不是一个静态界面,而是一个正在呼吸、正在响应你每一次操作的活系统。

5. 常见问题与排查技巧实录:那些文档里不会写的“血泪教训”

5.1 “编译失败:找不到命名空间HuiLian.Data”——项目引用丢失的真相

这是新手遇到的第一道坎。明明HuiLian.Data.csproj就在解决方案里,为什么HuiLian.Cloud项目里using HuiLian.Data;会报红?根本原因只有一个:项目引用没有建立

在解决方案资源管理器里,展开HuiLian.Cloud项目,找到“引用”节点,右键→“添加引用”。在弹出的窗口里,左侧勾选“项目”,然后在右侧列表里,把HuiLian.DataHuiLian.ModelHuiLian.Common这三个项目全部勾上,点击“确定”。这时,HuiLian.Cloud项目下的“引用”里,就会出现这三个项目的图标。再重新编译,错误消失。

提示:这个操作之所以容易被忽略,是因为很多教程假设你从Git克隆的是一个完整的、引用关系已配置好的解决方案。但如果你是从压缩包里解压出来的文件,或者手动复制了.csproj文件,VS并不会自动帮你建立项目间的引用关系。这是VS的机制,不是代码bug。

5.2 “运行时报错:无法连接到SQL Server”——连接字符串的魔鬼细节

错误信息通常是:“A network-related or instance-specific error occurred while establishing a connection to SQL Server…”。这几乎100%是App.config里的连接字符串出了问题。排查步骤如下:

  1. 确认SQL Server服务是否在运行:按Win+R,输入services.msc,在服务列表里找到SQL Server (SQLEXPRESS),确保其状态是“正在运行”。如果不是,右键它→“启动”。
  2. 确认实例名是否正确:打开SSMS,尝试用Windows身份验证连接。如果连接不上,说明实例名错了。在SSMS的“连接到服务器”窗口,服务器名称一栏,尝试输入localhost127.0.0.1..\SQLEXPRESSYOURPCNAME\SQLEXPRESS,挨个试,直到能连上为止。把你成功的那个实例名,填进App.configData Source=后面。
  3. 确认数据库名是否正确:在SSMS里,展开“数据库”,看看左边是否真的有一个叫HuiLianDB的数据库。名字必须完全一致,包括大小写(虽然SQL Server默认不区分,但保险起见)。
  4. 确认身份验证模式Integrated Security=True意味着用当前Windows账户登录。确保你登录Windows的账户,有权限访问SQL Server。如果不行,可以改成SQL Server认证:把Integrated Security=True删掉,加上User ID=sa;Password=你的sa密码;

5.3 “扫码没反应”——键盘钩子与焦点的隐秘战争

你把扫码枪接到电脑上,对着商品扫,“嘀”一声,但界面上什么都没发生。别急着怀疑扫码枪坏了,这90%是焦点问题。

HuiLian.Cloud的扫码逻辑,是监听全局的KeyDown事件,但它有一个前提:主窗口必须拥有键盘焦点。如果你在扫码前,不小心点了桌面上的某个其他程序(比如记事本),那么MainWindow就失去了焦点,它的KeyDown事件就不会被触发。

解决方法很简单:在扫码前,用鼠标点击一下MainWindow的任意空白区域(比如标题栏),确保窗口边框变亮,表示它已获得焦点。或者,更彻底的办法,修改MainWindow.xaml.cs里的OnKeyDown方法,在开头加一行强制获取焦点的代码:

private void OnKeyDown(object sender, KeyEventArgs e) { this.Activate(); // 强制激活窗口,获取焦点 // ... 后续的扫码逻辑 }

这行代码会让窗口在每次按键前,都把自己拉到前台,彻底杜绝焦点丢失的问题。这是我在给客户部署时,总结出的最有效的“防呆”措施。

5.4 “打印小票失败”——不是代码问题,是驱动和纸宽的陷阱

项目里集成了小票打印功能(PrintHelper.PrintReceipt(order)),但很多用户反馈“点打印没反应”。经过大量现场排查,我发现根本原因从来不在C#代码,而在于打印机驱动和纸张宽度的匹配

小票打印机(如常见的热敏打印机)通常有两种驱动模式:ESC/POS指令模式和通用文本模式。HuiLian.Cloud的打印逻辑,是向打印机发送纯文本(ASCII)和简单的ESC指令(如换行\n、切纸\x1D\x56\x00)。这要求打印机必须工作在“通用文本”或“兼容模式”下。

排查步骤:
1. 在Windows“设置”→“设备”→“打印机和扫描仪”里,找到你的小票打印机,右键→“管理”→“打印首选项”。
2. 在“纸张/质量”选项卡里,找到“纸张尺寸”或“介质类型”,把它设置为“自定义”,宽度设为80mm(这是最常见的小票纸宽)。
3. 在“端口”选项卡里,确认端口是USB001LPT1,而不是FILE:(那是保存为文件)。
4. 最关键一步:在“高级”选项卡里,找到“打印处理器”,把它从默认的WINPRINT,改成TEXT。这个改动,会强制打印机把所有发送过来的数据,都当作纯文本处理,而不是试图解析成图形。

做完这四步,重启打印机,再试打印,99%的问题都能解决。记住,小票打印是个“软硬件协同”的活,代码只是发指令的人,最终执行靠的是驱动和硬件的默契。

6. 二次开发与定制化指南:如何把它变成你自己的收银系统

6.1 添加新功能:以“会员积分”为例,手把手带你改三层

假设你想给系统加上会员积分功能,让顾客结账时能输入会员卡号,系统自动累加积分。这是一个典型的二次开发场景,我们来拆解如何在现有架构上安全地扩展。

第一步:在Model层添加实体
打开HuiLian.Model项目,新建一个类Member.cs

namespace HuiLian.Model { public class Member { public int Id { get; set; } public string CardNumber { get; set; } // 会员卡号 public string Name { get; set; } public decimal Points { get; set; } // 当前积分 public DateTime CreatedTime { get; set; } } }

第二步:在Data层添加数据访问
HuiLian.Data项目里,新建MemberDAL.cs。参考ProductDAL.cs的风格,写两个核心方法:

public static class MemberDAL { public static Member GetByCardNumber(string cardNumber) { string sql = "SELECT Id, CardNumber, Name, Points, CreatedTime FROM Members WHERE CardNumber = @cardNumber"; // ... 执行查询,返回Member对象(代码同ProductDAL) } public static void AddPoints(int memberId, decimal pointsToAdd) { string sql = "UPDATE Members SET Points = Points + @points WHERE Id = @id"; // ... 执行UPDATE(代码同ProductDAL.UpdateStock) } }

同时,在DatabaseScripts\CreateTables.sql里,加上创建Members表的SQL语句。

第三步:在UI层集成
打开MainWindow.xaml,在结算区域(<Grid Grid.Row="4">)里,添加一个TextBox用于输入会员卡号,和一个Button用于查询:

<TextBox x:Name="txtMemberCard" Width="150" Margin="5" /> <Button Content="查询会员" Click="OnQueryMemberClick" Margin="5" /> <TextBlock x:Name="lblMemberInfo" Margin="5" />

然后在MainWindow.xaml.cs里,添加事件处理方法:

private void OnQueryMemberClick(object sender, RoutedEventArgs e) { string cardNumber = txtMemberCard.Text.Trim(); if (!string.IsNullOrEmpty(cardNumber)) { var member = MemberDAL.GetByCardNumber(cardNumber); if (member != null) { lblMemberInfo.Text = $"欢迎 {member.Name}!当前积分:{member.Points}"; // 把member对象存到一个私有字段,供后续结算时使用 _currentMember = member; } else { MessageBox.Show("未找到该会员,请检查卡号"); } } }

最后,在CreateOrder逻辑里(OrderDAL.CreateOrder方法),加入积分累加的代码:MemberDAL.AddPoints(_currentMember.Id, order.TotalAmount * 10);(假设1元=10积分)。

整个过程,你没有动HuiLian.Cloud项目的任何核心逻辑,只是在对应的层里,添加了新的、职责单一的代码。这就是良好分层架构的魅力:扩展新功能,就像往一个已经搭好的架子上挂新零件,而不是推倒重来

6.2 修改UI样式:从蓝色主题到你的品牌色

Style文件夹是整个项目的视觉中枢。它里面存放着App.xaml引用的ResourceDictionary,定义了所有控件的默认样式。如果你想把主色调从蓝色改成你们超市的绿色,只需修改Style\Colors.xaml

<!-- 原来的蓝色 --> <Color x:Key="PrimaryColor">#2196F3</Color> <!-- 改成你们的绿色 --> <Color x:Key="PrimaryColor">#4CAF50</Color>

然后,所有用到{StaticResource PrimaryColor}的地方(按钮背景、标题栏、进度条),都会自动变成绿色。WPF的资源字典机制,让你能用最少的代码,完成全站样式的统一替换。

注意:Style\Controls.xaml里定义了ButtonTextBox等控件的模板。如果你想让按钮有圆角、阴影,就在这里修改<ControlTemplate>。但切记,不要为了炫酷而牺牲可用性——收银员戴着手套操作,按钮必须足够大,点击区域必须明确。

6.3 部署发布:如何打包成一个.exe,让小店老板双击就能用

Visual Studio自带的“发布”功能,对.NET Framework项目来说,有点“杀鸡用牛刀”。最简单、最可靠的方式,是使用“安装项目”(Setup Project),但VS Community版不支持。所以,我们采用“绿色免安装”方案:

  1. 在解决方案资源管理器里,右键HuiLian.Cloud项目→“属性”→“发布”选项卡→点击“应用程序文件…”按钮。
  2. 在弹出的窗口里,确保HuiLian.Cloud.exe的“发布状态”是“包括”,所有依赖的DLL(如HuiLian.Data.dllHuiLian.Model.dll)也都是“包括”。
  3. 点击“发布”按钮,选择一个文件夹(比如C:\MyPublish)。
  4. 发布完成后,打开C:\MyPublish\Application Files\HuiLian.Cloud_<version>\文件夹,里面有一个.application文件和一个HuiLian.Cloud.exe.deploy文件。
  5. HuiLian.Cloud.exe.deploy重命名为HuiLian.Cloud.exe,然后把这个exe,连同HuiLian.Cloud.exe.config(即App.config的发布版)、HuiLian.Data.dllHuiLian.Model.dllHuiLian.Common.dllSystem.Data.SqlClient.dll(如果packages.config里有引用)这几个文件,全部复制到一个新的空文件夹里。
  6. 把这个文件夹打包成ZIP,发给小店老板。老板解压后,双击HuiLian.Cloud.exe,系统就启动了。

这个方案生成的,就是一个真正的“绿色软件”,没有任何注册表写入,卸载就是删文件夹。对于小店老板来说,简单、安全、无负担。

我个人在实际操作中的体会是,这套HuiLian.Cloud源码的价值,不在于它有多“高大上”,而在于它把一个看似复杂的收银系统,拆解成了一个个可触摸、可理解、可修改的零件。它没有回避数据库连接的繁琐,没有隐藏扫码逻辑的细节,更没有用花哨的框架把业务逻辑层层包裹。它就像一本摊开的、写满批注的教科书,告诉你一个真实的收银系统,从第一行代码到最后一张小票,究竟是怎样一步步运转起来的。如果你正站在WPF开发的门口,或者正为小店寻找一个靠谱的收银底座,那么,不妨就从这行F5开始。

本文还有配套的精品资源,点击获取

简介:直接可运行的C# WPF超市收银系统工程,结构清晰,包含MainWindow.xaml等完整前端界面文件、App.xaml.cs和Program.cs等核心逻辑代码,以及HuiLian.Data、HuiLian.Model、HuiLian.Common等分层项目模块。数据库操作封装在DataAccess目录下,使用标准packages.config管理NuGet依赖,支持商品录入、扫码结算、订单查看等基础零售收银流程。配套5张真实运行截图(如20230221223542.png),覆盖主界面、结算页、商品列表等关键场景;附带中英文README、MIT许可证、ISSUE和PR模板,便于学习WPF MVVM实践、理解零售业务数据流或快速定制改造。解决方案为标准.NET Framework格式(HuiLian.Cloud.sln),图标、样式资源、配置文件齐全,开箱即编译调试。


本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询