抖音粉丝群1
『7x24小时有问必答』

前言

零售门店里,收银系统是每天被使用上百次的工具。但很多系统界面老旧、操作卡顿,甚至在高分屏或触控设备上显示错乱,严重影响效率和体验。有没有可能在 Windows 平台上做出一款既好看又好用、还能真正适配现代硬件的收银软件?
本文推荐一个基于 Ant Design 设计语言,WinForm 开发的收银系统。

项目介绍

一个基于 Ant Design 设计语言开发的桌面收银系统,采用 WinForms 技术实现。它不是为了炫技,而是希望把 Web 端常见的简洁交互和视觉美感,带到一线收银场景中。项目面向中小型商超、便利店等真实业务环境,目标是让普通店员也能轻松上手、高效操作。

项目功能

1、支持商品扫码快速录入,兼容主流扫码枪设备
2、提供多种购物车样式,可按屏幕尺寸或使用习惯自由切换
3、内置完整促销引擎,覆盖限时特价、满减送、组合折扣、整单换购、买一送一等常见营销策略
4、支持现金、微信、支付宝等多种支付方式(含模拟)
5、集成小票打印与钱箱控制,适配主流热敏打印机
6、具备异常断电恢复机制,重启后可还原未完成订单
7、支持操作日志记录,便于事后追溯与审计
8、可配置多语言界面,满足国际化或双语门店需求

项目特点

全局采用 Ant Design 风格 UI,界面清爽、布局合理
支持一键切换主题色,节日活动可快速更换氛围配色
图标系统可整体替换,如圣诞期间自动加载节日主题图标
自动跟随 Windows 系统浅色/深色模式,视觉体验更统一
全面适配高 DPI 屏幕,在 2K/4K 触控一体机上显示清晰
针对触屏操作优化按钮大小与间距,减少误触
启动快、资源占用低,适合长时间运行在商用终端
交互逻辑贴近一线员工习惯,几乎无需培训即可上手

项目技术

UI 框架:WinForms + 自定义 Ant Design 风格控件
数据访问:FreeSql(高性能国产 ORM,支持多数据库)
状态管理:ReactiveUI(提升响应式编程能力)
缓存依赖:Redis(用于促销规则、临时订单等高频数据)
运行环境:兼容 .NET Framework 4.0/4.8 及 .NET 6.0/.NET 9.0
全球化支持:基于资源文件的多语言切换机制
DPI 适配:启用 AutoScaleMode 与手动布局微调结合
硬件集成:通过标准指令控制钱箱与热敏打印机

项目代码

设置支付页面的数据绑定、事件监听和交互逻辑
private  void  InitBinding()

{

       var  parentViewModel = Locator.Current.GetService<mainviewmodel>();

      ViewModel = Locator.Current.GetService<payviewmodel>();

      ViewModel.TotalAmount = parentViewModel.TotalAmount;

      ViewModel.TotalCount = parentViewModel.TotalCount;

      ViewModel.TotalDiscount = parentViewModel.TotalDisAmount;

       this.WhenActivated(d =>

      {

             this.Events().Load

                  .Do(x =>  

                  {  

                        ActiveControl = input_input;  

                        input_input.SelectAll();  

                  })

                  .Subscribe()

                  .DisposeWith(d);

             this.Bind(ViewModel,

                  vm => vm.PayList,

                  v => v.payGrid.DataSource

                  ).DisposeWith(d);

             this.Bind(ViewModel,

                  vm => vm.PayAmountString,

                  v => v.input_input.Text

                  ).DisposeWith(d);

             this.OneWayBind(ViewModel,

                  vm => vm.PayTitle,

                  v => v.label_total.Text

                  ).DisposeWith(d);

             this.OneWayBind(ViewModel,

                  vm => vm.PaySubTitle,

                  v => v.label_paid.Text

                  ).DisposeWith(d);

             this.Events().KeyPress

                  .Do(e =>

            {

                   int  key = Convert.ToInt32(e.KeyChar);

                   // 数字、backspace、dot

                   if  (!(48  <= key && key <=  58  || key ==  8  || key ==  46))

                  {

                        e.Handled =  true;

                  }

            })

                  .Subscribe()

                  .DisposeWith(d);

             this.Events().Closing

                  .Do(x =>

            {

                  ViewModel.ResetCommand.Execute().Subscribe();

                   this.Dispose();

            })

                  .Subscribe()

                  .DisposeWith(d);

             //添加支付后处理

            MessageBus.Current.Listen<addpayeventargs>()

                  .ObserveOn(RxApp.MainThreadScheduler)

                  .Subscribe(e =>

                  {

                        Console.WriteLine(e.Pays.Count >  0  ? e.Pays.FirstOrDefault().PayName :  "触发");

                        CreateTag(e);

                  });

             //结账成功处理

            MessageBus.Current.Listen<settlepayeventargs>()

                  .ObserveOn(RxApp.MainThreadScheduler)

                  .Subscribe(e =>

                  {

                         var  result = e.Result;

                         if  (result.Success)

                        {

                              pageHeader_title.SubText +=  "(退出键退出)";

                              label_total.Text +=  $",找零{ViewModel.ExchangeAmount}元";

                               if  (MessageBox.Show("是否打印小票?",  "提醒", MessageBoxButtons.YesNo, MessageBoxIcon.Asterisk, MessageBoxDefaultButton.Button2) == DialogResult.Yes)

                              {

                                     //这里放打印逻辑

                              }

                               if  (ViewModel.ExchangeAmount ==  0)

                              {

                                    Close();

                              }

                        }

                         else

                        {

                               var  config =  new  Notification.Config(Globals.MainForm,  "结账", result.Message, TType.Error, TAlignFrom.Top);

                              Notification.open(config);

                              ActiveControl = input_input;

                              input_input.Focus();

                              input_input.Select();

                        }

                  });

      });

}

项目效果

扫码响应迅速,促销计算实时准确,界面滑动流畅无卡顿。即使突然断电,重启后也能恢复未结账的购物车,避免顾客重复排队。触屏操作体验良好,按钮大小适中,手指点击精准。
系统登录
1.png
系统首页
2.png

3.png

4.png

5.png

6.png

7.png

暗黑主题

8.png

项目源码

代码结构清晰,模块划分合理。无论是对接自有硬件设备、扩展新的促销类型,还是集成 ERP 或库存系统,项目都预留了良好的扩展接口。
Gitee:https://gitee.com/cookies_code/boundless

总结

总的来说,Boundless 并没有追求最前沿的技术栈,而是解决一个具体而真实的痛点:让收银这件事变得更简单、更高效、更愉悦。它证明了即使是 WinForms 这样的传统平台,只要用心打磨细节,依然能做出符合现代审美和使用习惯的产品。对于预算有限但又不愿将就的中小商户来说,这是一个值得尝试的开源项目。

关键词

WinForms、Ant Design、收银系统FreeSqlRedis触屏适配促销引擎、DPI 自适应、多语言ReactiveUI
最后
如果你觉得这篇文章对你有帮助,不妨点个赞支持一下!你的支持是我继续分享知识的动力。如果有任何疑问或需要进一步的帮助,欢迎随时留言。也可以加入微信公众号[DotNet技术匠]  社区,与其他热爱技术的同行一起交流心得,共同成长!
作者:小码编匠
出处:gitee.com/smallcore/DotNetCore
声明:网络内容,仅供学习,尊重版权,侵权速删,歉意致谢!

END

方便大家交流、资源共享和共同成长
纯技术交流群,需要加入的小伙伴请扫码,并备注加群

推荐阅读

觉得有收获?不妨分享让更多人受益
关注「DotNet技术匠」,共同提升技术实力

收藏
点赞
分享
在看
</settlepayeventargs></addpayeventargs></payviewmodel></mainviewmodel>

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

上一主题上一主题         下一主题下一主题
QQ手机版小黑屋粤ICP备17165530号

关于我们·投诉举报· 用户帮助· 联系我们 · 本站服务 · 版权声明· 隐私政策 · 投搞指南

法律保护:PLC技术网,plcjs.com,plcjs.net等字样
Copyright 2010-2030. All rights reserved. 


微信公众号二维码 抖音二维码 百家号二维码 今日头条二维码哔哩哔哩二维码