告别WinForm重写噩梦!.NET8+Avalonia实现C#工业上位机Windows/统信UOS双平台兼容,成本直降90%

张开发
2026/4/10 10:16:38 15 分钟阅读

分享文章

告别WinForm重写噩梦!.NET8+Avalonia实现C#工业上位机Windows/统信UOS双平台兼容,成本直降90%
做工业自动化上位机开发的C#程序员最近两年是不是被“国产化替代”的需求逼疯了前两年在汽车零部件焊接产线做项目客户原来用的是Windows 10工控机WinForm上位机运行得好好的。去年突然接到通知所有新上产线必须用统信UOS V20国产操作系统旧产线也要在1年内完成迁移。我当时头都大了原来的WinForm上位机有10万多行代码用了DevExpress、HslCommunication这些Windows生态的库重写一套WPF Avalonia UI周期至少要6个月成本至少要50万客户根本等不起也付不起。后来我抱着试一试的心态用.NET 8 Avalonia做了一套跨平台迁移方案结果超出预期核心业务逻辑代码零修改只花了2周时间重写UI层就实现了Windows 10/11和统信UOS V20的双平台兼容旧产线的迁移成本从50万降到5万直降90%新产线的开发周期从6个月降到1个月缩了80%而且性能和Windows原生WinForm几乎一样连续跑了72小时内存稳定在320MB左右没有任何泄漏。国产化替代是工业自动化的大趋势统信UOS、麒麟这些国产Linux操作系统已经在很多行业汽车、电力、军工、医疗强制推广。而.NET 8 Avalonia的组合是C#工业上位机跨平台迁移的最优解不用重写核心业务逻辑不用换编程语言不用换开发工具就能快速实现双平台兼容。今天这篇文章我就结合自己2年的跨平台迁移经验从零到一教你实现C#工业上位机的Windows/国产Linux双平台兼容所有方案都是产线验证过的哪怕你是第一次接触Avalonia跟着做也能一步到位落地。一、为什么工业上位机跨平台首选.NET 8 Avalonia在工业自动化领域跨平台方案的选择永远是稳定优先、性能为王、生态成熟、迁移成本低而.NET 8 Avalonia的组合完美满足了这四个核心需求1.1 .NET 8的核心优势跨平台原生支持.NET 8是微软发布的最新LTS版本原生支持Windows、Linux、macOS、统信UOS、麒麟等几乎所有主流操作系统不用再依赖Mono这种第三方跨平台框架工业级性能优化.NET 8对GC、JIT、AOT都做了深度优化性能比.NET 6提升了20%以上和Windows原生.NET Framework几乎一样成熟的工业生态HslCommunication、Modbus.Net、OPC UA .NET Standard这些工业通信库都原生支持.NET 8不用再找替代库AOT编译支持.NET 8支持Native AOT编译可以把C#代码编译成原生机器码启动速度更快内存占用更低还能保护代码不被反编译完美满足工业场景的安全要求。1.2 Avalonia的核心优势跨平台UI框架Avalonia是一个开源的、跨平台的、XAML驱动的UI框架和WPF的API几乎一样WPF开发者可以无缝迁移工业级控件生态Avalonia UI有官方的Avalonia.Controls.DataGrid、Avalonia.Controls.TreeView还有第三方的AvaloniaUI.LiveCharts2实时曲线、AvaloniaUI.DevExpress收费工业场景首选、AvaloniaUI.MaterialDesign开源免费UI美观完全满足工业上位机的UI需求硬件加速支持Avalonia支持OpenGL、Vulkan、DirectX硬件加速实时曲线、3D模型渲染的性能和WPF几乎一样国产操作系统适配Avalonia官方已经对统信UOS、麒麟这些国产Linux操作系统做了深度适配不用再自己解决字体、输入法、权限这些问题。二、整体跨平台迁移架构设计我们设计了一套分层解耦的跨平台迁移架构从硬件层、通信层、业务逻辑层、UI适配层到部署层每一层都独立可替换核心业务逻辑代码零修改只需要重写UI适配层整体架构如下部署层Windows部署包统信UOS/麒麟部署包Docker容器化部署UI适配层Avalonia XAML UI跨平台UI控件跨平台文件操作跨平台日志记录业务逻辑层数据采集与解析数据计算与存储报警规则判定设备控制逻辑通信层HslCommunication/Modbus.NetOPC UA .NET Standard跨平台串口库硬件层PLC/工业相机/传感器千兆以太网/RS485这套架构的核心设计亮点分层解耦硬件层、通信层、业务逻辑层、UI适配层、部署层完全分离核心业务逻辑代码零修改UI适配层最小化只把和UI相关的代码XAML、事件处理、跨平台文件操作放在UI适配层其他代码全放在业务逻辑层跨平台通信库统一用HslCommunication、OPC UA .NET Standard这些原生支持.NET 8的跨平台通信库不用再找替代库跨平台部署灵活支持Windows部署包、统信UOS/麒麟部署包、Docker容器化部署适配不同的客户需求。三、核心跨平台迁移步骤3.1 环境准备开发工具Visual Studio 2022Windows或者JetBrains RiderWindows/Linux/macOS推荐用Rider跨平台开发更方便.NET版本.NET 8 LTSAvalonia模板在Visual Studio 2022中搜索“Avalonia”安装“Avalonia for Visual Studio 2022”模板或者在JetBrains Rider中搜索“Avalonia”安装“Avalonia Plugin”国产Linux测试环境在VMware Workstation或者VirtualBox中安装统信UOS V20或者麒麟V10 SP3用于测试跨平台兼容性。3.2 项目结构重构首先我们要把原来的WinForm/WPF项目重构成分层解耦的结构核心业务逻辑代码零修改只需要把UI相关的代码分离出来。重构后的项目结构IndustrialHmiCrossPlatform ├── IndustrialHmi.Core # 核心业务逻辑层零修改 │ ├── Models # 数据模型 │ ├── Services # 业务服务数据采集、计算、存储、报警 │ ├── Interfaces # 接口定义 │ └── Utils # 工具类跨平台兼容的工具类 ├── IndustrialHmi.Communication # 通信层零修改用跨平台库 │ ├── ModbusService.cs │ ├── OpcUaService.cs │ └── SerialPortService.cs ├── IndustrialHmi.Avalonia # UI适配层唯一需要重写的层 │ ├── Views # XAML视图 │ ├── ViewModels # MVVM视图模型 │ ├── App.axaml # 应用程序入口 │ └── App.axaml.cs └── IndustrialHmi.Tests # 单元测试3.3 核心业务逻辑代码零修改原来的WinForm/WPF项目中的核心业务逻辑代码数据采集、计算、存储、报警只要用的是.NET Standard或者.NET 6的跨平台库就可以直接复制到IndustrialHmi.Core和IndustrialHmi.Communication项目中零修改。注意事项不要用Windows原生的API比如System.Windows.Forms.MessageBox、System.IO.Ports.SerialPort要用跨平台的替代库不要用Windows原生的文件路径分隔符\要用Path.DirectorySeparatorChar或者Path.Combine()不要用Windows原生的日志库比如EventLog要用跨平台的日志库比如Serilog、NLog。3.4 UI适配层重写唯一需要重写的层Avalonia的XAML和WPF的XAML几乎一样WPF开发者可以无缝迁移。我们用MVVM模式重写UI适配层把视图和视图模型分离方便后续维护和测试。3.4.1 安装必要的NuGet包在IndustrialHmi.Avalonia项目中安装以下NuGet包AvaloniaAvalonia核心库Avalonia.DesktopAvalonia桌面平台支持Avalonia.DiagnosticsAvalonia调试工具开发环境用生产环境可以去掉AvaloniaUI.LiveCharts2实时曲线库开源免费CommunityToolkit.MvvmMVVM工具库简化MVVM代码Serilog跨平台日志库Serilog.Sinks.Console控制台日志输出Serilog.Sinks.File文件日志输出。3.4.2 应用程序入口重写重写App.axaml和App.axaml.cs设置应用程序的主窗口和主题。App.axamlApplication xmlnshttps://github.com/avaloniaui xmlns:xhttp://schemas.microsoft.com/winfx/2006/xaml x:ClassIndustrialHmi.Avalonia.App Application.Styles !-- 官方默认主题 -- FluentTheme ModeLight/ !-- 或者用MaterialDesign主题 -- !-- StyleInclude Sourceavares://AvaloniaUI.MaterialDesign/Themes/MaterialDesignLight.axaml/ -- /Application.Styles /ApplicationApp.axaml.csusingAvalonia;usingAvalonia.Controls.ApplicationLifetimes;usingAvalonia.Markup.Xaml;usingIndustrialHmi.Avalonia.Views;usingSerilog;namespaceIndustrialHmi.Avalonia{publicpartialclassApp:Application{publicoverridevoidInitialize(){AvaloniaXamlLoader.Load(this);// 初始化跨平台日志Log.LoggernewLoggerConfiguration().MinimumLevel.Information().WriteTo.Console().WriteTo.File(logs/hmi-.log,rollingInterval:RollingInterval.Day).CreateLogger();}publicoverridevoidOnFrameworkInitializationCompleted(){if(ApplicationLifetimeisIClassicDesktopStyleApplicationLifetimedesktop){desktop.MainWindownewMainWindow();// 窗口关闭时释放资源desktop.Exit(sender,e){Log.CloseAndFlush();};}base.OnFrameworkInitializationCompleted();}}}3.4.3 主窗口重写重写MainWindow.axaml和MainWindow.axaml.cs用MVVM模式绑定数据。MainWindow.axamlWindow xmlnshttps://github.com/avaloniaui xmlns:xhttp://schemas.microsoft.com/winfx/2006/xaml xmlns:vmusing:IndustrialHmi.Avalonia.ViewModels xmlns:lvcusing:LiveChartsCore.SkiaSharpView.Avalonia x:ClassIndustrialHmi.Avalonia.Views.MainWindow Title工业上位机跨平台版 Width1280 Height720 WindowStartupLocationCenterScreen Window.DataContext vm:MainWindowViewModel/ /Window.DataContext Grid Grid.RowDefinitions RowDefinition HeightAuto/ RowDefinition Height*/ RowDefinition HeightAuto/ /Grid.RowDefinitions !-- 顶部菜单栏 -- Menu Grid.Row0 MenuItem Header文件 MenuItem Header退出 Command{Binding ExitCommand}/ /MenuItem MenuItem Header帮助 MenuItem Header关于 Command{Binding AboutCommand}/ /MenuItem /Menu !-- 中间内容区 -- Grid Grid.Row1 Margin10 Grid.ColumnDefinitions ColumnDefinition Width2*/ ColumnDefinition Width3*/ /Grid.ColumnDefinitions !-- 左侧实时数据显示区 -- StackPanel Grid.Column0 Margin0,0,10,0 TextBlock Text实时数据 FontSize18 FontWeightBold Margin0,0,0,10/ DataGrid ItemsSource{Binding TemperatureData} AutoGenerateColumnsFalse IsReadOnlyTrue DataGrid.Columns DataGridTextColumn Header传感器ID Binding{Binding SensorId}/ DataGridTextColumn Header温度(℃) Binding{Binding Temperature, StringFormatF2}/ DataGridTextColumn Header状态 Binding{Binding Status}/ /DataGrid.Columns /DataGrid /StackPanel !-- 右侧实时曲线区 -- StackPanel Grid.Column1 TextBlock Text实时温度曲线 FontSize18 FontWeightBold Margin0,0,0,10/ lvc:CartesianChart Series{Binding TemperatureSeries} ZoomModeX/ /StackPanel /Grid !-- 底部状态栏 -- StatusBar Grid.Row2 StatusBarItem TextBlock Text{Binding StatusBarText}/ /StatusBarItem /StatusBar /Grid /WindowMainWindow.axaml.csusingAvalonia.Controls;namespaceIndustrialHmi.Avalonia.Views{publicpartialclassMainWindow:Window{publicMainWindow(){InitializeComponent();}}}3.4.4 视图模型重写用CommunityToolkit.Mvvm简化MVVM代码绑定数据和命令。MainWindowViewModel.csusingCommunityToolkit.Mvvm.ComponentModel;usingCommunityToolkit.Mvvm.Input;usingIndustrialHmi.Core.Models;usingIndustrialHmi.Core.Services;usingLiveChartsCore;usingLiveChartsCore.SkiaSharpView;usingSystem;usingSystem.Collections.ObjectModel;usingSystem.Threading.Tasks;namespaceIndustrialHmi.Avalonia.ViewModels{publicpartialclassMainWindowViewModel:ObservableObject{// 温度数据服务从核心业务逻辑层注入privatereadonlyITemperatureService_temperatureService;// 实时数据显示集合[ObservableProperty]privateObservableCollectionTemperatureModel_temperatureDatanewObservableCollectionTemperatureModel();// 实时温度曲线系列[ObservableProperty]privateISeries[]_temperatureSeriesArray.EmptyISeries();// 状态栏文本[ObservableProperty]privatestring_statusBarText系统初始化中...;// 控制数据采集的标志privatevolatilebool_isRunningfalse;// 数据采集任务privateTask_dataAcquisitionTask;publicMainWindowViewModel(){// 这里可以用依赖注入简化代码_temperatureServicenewTemperatureService();// 初始化实时温度曲线InitializeTemperatureSeries();// 启动数据采集StartDataAcquisition();}// 初始化实时温度曲线privatevoidInitializeTemperatureSeries(){TemperatureSeriesnewISeries[]{newLineSeriesdouble{Name传感器1,ValuesnewObservableCollectiondouble(),Fillnull},newLineSeriesdouble{Name传感器2,ValuesnewObservableCollectiondouble(),Fillnull}};}// 启动数据采集privatevoidStartDataAcquisition(){if(_isRunning)return;_isRunningtrue;StatusBarText系统运行中...;// 启动数据采集任务_dataAcquisitionTaskTask.Run(async(){while(_isRunning){try{// 从核心业务逻辑层获取温度数据vartempsawait_temperatureService.GetTemperatureDataAsync();// 更新UI用Dispatcher不要阻塞后台线程awaitApp.Current.Dispatcher.InvokeAsync((){// 更新实时数据显示集合TemperatureData.Clear();foreach(vartempintemps){TemperatureData.Add(temp);}// 更新实时温度曲线if(TemperatureSeries[0]isLineSeriesdoubleseries1temps.Count0){series1.Values.Add(temps[0].Temperature);if(series1.Values.Count100){series1.Values.RemoveAt(0);}}if(TemperatureSeries[1]isLineSeriesdoubleseries2temps.Count1){series2.Values.Add(temps[1].Temperature);if(series2.Values.Count100){series2.Values.RemoveAt(0);}}});// 每500ms采集一次awaitTask.Delay(500);}catch(Exceptionex){StatusBarText$数据采集失败{ex.Message};awaitTask.Delay(1000);}}});}// 退出命令[RelayCommand]privatevoidExit(){_isRunningfalse;if(_dataAcquisitionTask!null){_dataAcquisitionTask.Wait();}App.Current.MainWindow.Close();}// 关于命令[RelayCommand]privateasyncTaskAbout(){awaitApp.Current.MainWindow.ShowMessageAsync(关于,工业上位机跨平台版\n基于.NET 8 Avalonia开发\n支持Windows/统信UOS/麒麟双平台);}}}四、跨平台部署4.1 Windows部署在Visual Studio 2022或者JetBrains Rider中选择“Release”配置右键IndustrialHmi.Avalonia项目选择“发布”发布目标选择“文件夹”部署模式选择“Self-contained”独立部署不需要客户安装.NET 8目标运行时选择“win-x64”点击“发布”即可。发布完成后把发布文件夹压缩成zip包发给客户客户解压后直接运行IndustrialHmi.Avalonia.exe即可。4.2 统信UOS/麒麟部署在Visual Studio 2022或者JetBrains Rider中选择“Release”配置右键IndustrialHmi.Avalonia项目选择“发布”发布目标选择“文件夹”部署模式选择“Self-contained”目标运行时选择“linux-x64”点击“发布”即可。发布完成后把发布文件夹压缩成tar.gz包上传到统信UOS/麒麟测试环境解压后给IndustrialHmi.Avalonia文件添加可执行权限然后运行即可# 解压tar.gz包tar-zxvfIndustrialHmi.Avalonia-linux-x64.tar.gz# 进入发布文件夹cdIndustrialHmi.Avalonia-linux-x64# 给可执行文件添加权限chmodx IndustrialHmi.Avalonia# 运行程序./IndustrialHmi.Avalonia注意事项统信UOS/麒麟默认没有安装中文字体需要安装中文字体比如思源黑体否则UI会显示乱码统信UOS/麒麟默认没有开放串口权限需要给当前用户添加dialout组sudo usermod -aG dialout $USER然后重启电脑如果需要开机自启动可以在统信UOS/麒麟的“启动器”中添加IndustrialHmi.Avalonia的快捷方式。五、实战案例汽车零部件焊接产线上位机跨平台迁移我们把这套方案用到汽车零部件焊接产线的上位机跨平台迁移中项目结构重构把原来的WinForm项目重构成分层解耦的结构核心业务逻辑代码零修改UI适配层重写用Avalonia重写UI层用LiveCharts2画实时温度、压力、电流曲线用DataGrid显示历史数据跨平台测试在Windows 10/11和统信UOS V20中测试性能和Windows原生WinForm几乎一样产线部署新上产线用统信UOS V20旧产线用Windows 10双平台兼容。迁移后的效果迁移成本从50万降到5万直降90%开发周期从6个月降到1个月缩了80%性能连续跑了72小时内存稳定在320MB左右没有任何泄漏双平台兼容Windows 10/11和统信UOS V20都能正常运行。写在最后.NET 8 Avalonia的组合是C#工业上位机跨平台迁移的最优解不用重写核心业务逻辑不用换编程语言不用换开发工具就能快速实现Windows/国产Linux双平台兼容。这套方案我已经在汽车零部件、PCB、五金件的多条产线稳定运行了2年所有方案都是经过实战验证的你只需要根据自己的实际需求调整就能直接用到自己的项目里。国产化替代是工业自动化的大趋势希望这篇文章能帮你解决跨平台迁移的难题快速完成工业上位机的国产化替代。

更多文章