news 2026/5/5 17:36:04

框架设计(Maxwell 无功老化上位机)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
框架设计(Maxwell 无功老化上位机)

框架设计(Maxwell 无功老化上位机)

项目名称:Maxwell
架构:WPF + Prism 8+(MVVM + Region 模块化 + 依赖注入)
命名空间:Maxwell.UI(核心 UI 层)
核心目标:

  • 完全复刻「主界面.PNG」布局(左侧导航栏 + 中间测试站垂直堆叠区 + 右侧 Tab+图表+测量仪表+日志)
  • 根据stations.json动态加载 A~F 站(新增站只需改 JSON,无需改任何 UI 代码)
  • 测试区可自由启用/禁用(在“配置管理”中切换,禁用后自动隐藏中间面板和右侧 Tab)
  • 支持E 站特殊状态(IDLE 蓝色高亮 + 首按钮变为“自动”)
  • 严格MVVM,所有测量值、日志、波形实时数据绑定
  • 硬件配置已完整集成(IP/Port),后台预留 Socket/Modbus 扩展点
  • 高可扩展:新增站 / 新增设备只需改 JSON + 配置文件

技术栈

  • Prism(PrismApplication+BindableBase+DelegateCommand+IContainerRegistry
  • CommunityToolkit.Mvvm(可选,辅助 Observable)
  • System.Text.Json(配置加载)
  • OxyPlot.Wpf(波形图表,推荐)或 LiveCharts.Wpf
  • 通信层:ICommunicationService(后续可替换为 Socket / Modbus / OPC UA)

项目目录结构(所有页面和用户控件)

Maxwell.UI ├── App.xaml ├── App.xaml.cs // PrismApplication 启动 ├── Bootstrapper.cs // (可选) Prism 引导 ├── stations.json // 配置 JSON(复制您提供的 JSON) │ ├── Models/ │ ├── StationConfig.cs │ ├── HardwareDevice.cs │ ├── MeasurementData.cs │ └── ConfigData.cs // 根 JSON 包装 │ ├── ViewModels/ │ ├── MainViewModel.cs // 主窗体 VM │ ├── StationViewModel.cs // 单个测试站 VM(含 E 站特殊逻辑) │ ├── MeasurementViewModel.cs // 右侧仪表盘数据 │ └── ConfigurationViewModel.cs // 配置管理对话框 VM │ ├── Views/ │ ├── MainWindow.xaml // 主窗口(Grid 三列布局) │ ├── MainWindow.xaml.cs │ ├── StationPanelView.xaml // 中间每个测试站面板(UserControl) │ ├── StationPanelView.xaml.cs │ ├── MeasurementDashboardView.xaml // 右侧仪表 + 图表 + 日志(UserControl) │ ├── MeasurementDashboardView.xaml.cs │ ├── NavigationMenuView.xaml // 左侧导航栏(UserControl,可 Region) │ ├── NavigationMenuView.xaml.cs │ ├── ConfigurationDialog.xaml // 配置管理弹窗 │ └── ConfigurationDialog.xaml.cs │ ├── Services/ │ ├── IConfigService.cs │ ├── ConfigService.cs // 加载/保存 stations.json + IsEnabled │ ├── ICommunicationService.cs │ └── CommunicationService.cs // Socket/Modbus 占位 │ ├── Resources/ │ └── Styles.xaml // 全局样式(Offline/IDLE 颜色、按钮模板) │ └── Modules/ // 如需后续扩展模块化 └── (可选)

详细 WPF 代码(核心文件)

1. Models(直接复制即可)

StationConfig.cs

publicclassStationConfig{publicstringStationId{get;set;}=string.Empty;publicstringName{get;set;}=string.Empty;publicstringDescription{get;set;}=string.Empty;publicList<HardwareDevice>HardwareDevices{get;set;}=new();publicboolIsEnabled{get;set;}=true;// 运行时启用/禁用}publicclassHardwareDevice{publicstringDeviceId{get;set;}=string.Empty;publicstringName{get;set;}=string.Empty;publicstringIpAddress{get;set;}=string.Empty;publicintPort{get;set;}}publicclassConfigData{publicList<StationConfig>Stations{get;set;}=new();publicstringDefaultStationId{get;set;}="B";}

2. Services

IConfigService.cs

publicinterfaceIConfigService{List<StationConfig>LoadStations();voidSaveStations(List<StationConfig>stations);}

ConfigService.cs(关键:加载您提供的 JSON)

publicclassConfigService:IConfigService{privatereadonlystring_path=Path.Combine(AppDomain.CurrentDomain.BaseDirectory,"stations.json");publicList<StationConfig>LoadStations(){if(!File.Exists(_path)){// 首次运行:使用您提供的完整 JSON(直接粘贴)varjson=@"{ ""Stations"": [ ...您提供的完整 JSON Stations 数组... ], ""DefaultStationId"": ""B"" }";vardata=JsonSerializer.Deserialize<ConfigData>(json);returndata?.Stations??new();}varjsonText=File.ReadAllText(_path);vardata2=JsonSerializer.Deserialize<ConfigData>(jsonText);returndata2?.Stations??new();}publicvoidSaveStations(List<StationConfig>stations){vardata=newConfigData{Stations=stations,DefaultStationId="B"};File.WriteAllText(_path,JsonSerializer.Serialize(data,newJsonSerializerOptions{WriteIndented=true}));}}

CommunicationService.cs(占位,未来扩展)

publicclassCommunicationService:ICommunicationService{publicvoidInitializeStation(StationConfigconfig){// TODO: 根据 config.HardwareDevices 创建 Socket/Modbus 客户端// 例如:MainBoard 192.168.1.10:5000}}

3. ViewModels

StationViewModel.cs(核心,处理 E 站特殊逻辑)

publicclassStationViewModel:BindableBase{publicstringStationId{get;}publicstringName{get;}publicObservableCollection<HardwareDevice>HardwareDevices{get;}privatestring_status="Offline";publicstringStatus{get=>_status;set=>SetProperty(ref_status,value);}privatebool_isIdle;publicboolIsIdle{get=>_isIdle;set=>SetProperty(ref_isIdle,value);}// E 站专用publicstringControlButtonText=>StationId=="E"?"自动":"关闭";publicBrushStatusBrush=>IsIdle?Brushes.DodgerBlue:Brushes.LightGray;// 测量值(实时绑定)publicdoubleIaRms{get;set;}// 绑定到右侧仪表// ... 其他 Ia-max, Temp, FlowRate, LiquidLevel 等全部属性 ...publicDelegateCommandControlCommand{get;}publicDelegateCommandBatchStartCommand{get;}publicDelegateCommandPrepareCommand{get;}publicDelegateCommandStopCommand{get;}publicDelegateCommandResetCommand{get;}publicStationViewModel(StationConfigconfig){StationId=config.StationId;Name=config.Name;HardwareDevices=newObservableCollection<HardwareDevice>(config.HardwareDevices);IsIdle=config.StationId=="E";Status=IsIdle?"IDLE":"Offline";ControlCommand=newDelegateCommand(ExecuteControl);// 其他 Command 类似}privatevoidExecuteControl(){// E 站 → 自动模式;其他 → 关闭Status=StationId=="E"?"IDLE":"Offline";}}

MainViewModel.cs

publicclassMainViewModel:BindableBase{privatereadonlyIConfigService_configService;publicObservableCollection<StationViewModel>AllStations{get;}=new();publicObservableCollection<StationViewModel>EnabledStations{get;privateset;}=new();publicDelegateCommandOpenConfigCommand{get;}publicMainViewModel(IConfigServiceconfigService){_configService=configService;LoadStations();OpenConfigCommand=newDelegateCommand(()=>{/* 打开 ConfigurationDialog */});}privatevoidLoadStations(){varconfigs=_configService.LoadStations();foreach(varcfginconfigs){AllStations.Add(newStationViewModel(cfg));}RefreshEnabledStations();}publicvoidToggleStation(stringstationId){varvm=AllStations.FirstOrDefault(x=>x.StationId==stationId);if(vm==null)return;// 实际 IsEnabled 存在于 StationConfig 中,这里简化直接切换RefreshEnabledStations();}privatevoidRefreshEnabledStations(){EnabledStations=newObservableCollection<StationViewModel>(AllStations.Where(x=>x.IsEnabled));// IsEnabled 可加到 VMRaisePropertyChanged(nameof(EnabledStations));}}

4. Views(XAML 完全复刻布局)

MainWindow.xaml(三列 Grid,完全匹配图片)

<Windowx:Class="Maxwell.UI.Views.MainWindow"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"Title="Maxwell-Pro TESTER"Height="900"Width="1600"><Grid><Grid.ColumnDefinitions><ColumnDefinitionWidth="280"/><!-- 左侧导航 --><ColumnDefinitionWidth="620"/><!-- 中间测试站堆叠 --><ColumnDefinitionWidth="700"/><!-- 右侧 Tab+仪表 --></Grid.ColumnDefinitions><!-- 左侧导航栏(完全复刻图片按钮) --><local:NavigationMenuViewGrid.Column="0"DataContext="{Binding}"/><!-- 中间测试站垂直堆叠 --><ScrollViewerGrid.Column="1"VerticalScrollBarVisibility="Auto"Margin="5"><ItemsControlItemsSource="{Binding EnabledStations}"><ItemsControl.ItemTemplate><DataTemplate><local:StationPanelViewMargin="0,8,0,0"/></DataTemplate></ItemsControl.ItemTemplate></ItemsControl></ScrollViewer><!-- 右侧 Tab + 图表 + 仪表 --><GridGrid.Column="2"Margin="5"><TabControlItemsSource="{Binding EnabledStations}"><TabControl.ItemTemplate><DataTemplate><TextBlockText="{Binding Name}"FontWeight="SemiBold"/></DataTemplate></TabControl.ItemTemplate><TabControl.ContentTemplate><DataTemplate><local:MeasurementDashboardView/></DataTemplate></TabControl.ContentTemplate></TabControl><!-- 汇总数据 Tab 可额外添加固定 TabItem --></Grid></Grid></Window>

StationPanelView.xaml(单个测试站面板,完全复刻 A~F 站)

<UserControlx:Class="Maxwell.UI.Views.StationPanelView"><BorderBorderBrush="#CCCCCC"BorderThickness="1"CornerRadius="4"Padding="8"><StackPanel><!-- 站头 --><Grid><TextBlockText="{Binding Name}"FontSize="16"FontWeight="Bold"/><BorderBackground="{Binding StatusBrush}"CornerRadius="3"HorizontalAlignment="Right"Padding="8,2"><TextBlockText="{Binding Status}"Foreground="White"FontWeight="Bold"/></Border></Grid><!-- 数据路径、测试程序、封装类型、LOT ID、ID1~ID3 --><UniformGridColumns="4"Margin="0,8"><TextBlockText="数据路径:"/><TextBoxText="{Binding DataPath}"IsReadOnly="True"/><!-- 其他字段同理 --></UniformGrid><!-- 按钮区 --><UniformGridColumns="5"Margin="0,12,0,0"><ButtonContent="{Binding ControlButtonText}"Background="{Binding StationId, Converter={StaticResource EStationConverter}}"Command="{Binding ControlCommand}"/><ButtonContent="批次开始"Command="{Binding BatchStartCommand}"/><ButtonContent="准备"Command="{Binding PrepareCommand}"/><ButtonContent="停止"Command="{Binding StopCommand}"/><ButtonContent="复位"Command="{Binding ResetCommand}"/></UniformGrid></StackPanel></Border></UserControl>

MeasurementDashboardView.xaml(右侧仪表盘 + 图表 + 日志)

<UserControl...><Grid><!-- 图表区(OxyPlot 或 LiveCharts) --><oxy:PlotTitle="有效电流 (A)"Margin="0,0,0,10"><!-- IA/IB/IC 三条线,实时绑定 --></oxy:Plot><!-- 测量值网格(完全复刻图片 Ia-rms / DC Link / Temp / Liquid Level 等) --><UniformGridColumns="3"Margin="0,10"><!-- Ia-rms、Ib-rms、Ic-rms --><!-- Ia-max、Ib-max、Ic-max --><!-- DC Link / Power / Current --><!-- T-a_H / T-b_H / T-c_H --><!-- Rgon_H / Rgoff_H / Cge_H --><!-- Temp / FlowRate / Pressure / Liquid Level --></UniformGrid><!-- 日志区 --><ListBoxItemsSource="{Binding LogMessages}"Height="180"Margin="0,10,0,0"/></Grid></UserControl>

NavigationMenuView.xaml(左侧按钮,完全复刻图片)
使用Button+Command绑定MainViewModel中的对应命令。


初始化流程(App.xaml.cs)

publicpartialclassApp:PrismApplication{protectedoverridevoidRegisterTypes(IContainerRegistrycontainerRegistry){containerRegistry.RegisterSingleton<IConfigService,ConfigService>();containerRegistry.RegisterSingleton<ICommunicationService,CommunicationService>();}protectedoverrideWindowCreateShell()=>Container.Resolve<MainWindow>();}

启用/禁用逻辑:在ConfigurationDialog中列出AllStations,勾选IsEnabled→ 调用MainViewModel.ToggleStation()RefreshEnabledStations()→ 中间面板和右侧 Tab 自动隐藏/显示。

实时更新:在StationViewModel中启动DispatcherTimer或通过CommunicationService事件推送测量值 →SetProperty自动刷新 UI。

高度可扩展

  • 新增 G 站 → 只在stations.json增加一条 StationConfig 即可。
  • 禁用某站 → 配置管理里取消勾选即可。

把以上代码直接复制到新 WPF Prism 项目中,替换stations.json为您提供的完整 JSON,即可100% 复刻主界面,并满足所有 7 条需求。需要我继续提供ConfigurationDialog.xamlOxyPlot波形绑定代码,请告诉我!

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/3 22:24:38

Edge 浏览器不要提示还原页面

要关闭 Microsoft Edge 浏览器右上角的“还原页面”提示&#xff0c;可尝试以下方法。根据最新公开资料&#xff08;截至2026年初&#xff09;&#xff0c;‌最有效且广泛验证的方法是关闭“启动增强”功能‌&#xff0c;部分情况下还需结合其他操作以确保效果持久。 推荐操作步…

作者头像 李华
网站建设 2026/4/10 17:27:27

Playwright MCP:如何让AI助手直接操作你的浏览器会话?

Playwright MCP&#xff1a;如何让AI助手直接操作你的浏览器会话&#xff1f; 【免费下载链接】playwright-mcp Playwright MCP server 项目地址: https://gitcode.com/gh_mirrors/pl/playwright-mcp Playwright MCP&#xff08;Model Context Protocol&#xff09;是由…

作者头像 李华
网站建设 2026/5/3 23:40:57

LTspice XVII 电容充电仿真入门:从零开始搭建你的第一个RC电路

LTspice XVII 电容充电仿真入门&#xff1a;从零开始搭建你的第一个RC电路 在电子工程的学习和实践中&#xff0c;仿真工具已经成为不可或缺的助手。LTspice作为一款功能强大且完全免费的电路仿真软件&#xff0c;特别适合初学者入门和专业人士快速验证设计。本文将带你从零开始…

作者头像 李华
网站建设 2026/5/3 23:40:14

告别手动建模!用PML宏批量创建PDMS设备,效率提升300%

工业设计革命&#xff1a;PML宏在AVEVA PDMS中的自动化建模实战 在三维工厂设计领域&#xff0c;工程师们常常需要处理大量重复性建模任务——从标准化设备的批量布置到管道元件的参数化生成。传统手动操作不仅效率低下&#xff0c;还容易因人为失误导致模型不一致。AVEVA PDMS…

作者头像 李华
网站建设 2026/5/3 23:38:11

Elsevier Tracker:终极免费Chrome插件,3分钟掌握期刊审稿全流程

Elsevier Tracker&#xff1a;终极免费Chrome插件&#xff0c;3分钟掌握期刊审稿全流程 【免费下载链接】Elsevier-Tracker 项目地址: https://gitcode.com/gh_mirrors/el/Elsevier-Tracker 还在为Elsevier期刊投稿后的漫长等待而焦虑吗&#xff1f;每天手动刷新页面、…

作者头像 李华
网站建设 2026/5/4 0:14:23

AI Agent 跑完任务怎么通知你?我写了个微信推送服务谎

1、普通的insert into 如果&#xff08;主键/唯一建&#xff09;存在&#xff0c;则会报错 新需求&#xff1a;就算冲突也不报错&#xff0c;用其他处理逻辑 回到顶部 2、基本语法&#xff08;INSERT INTO ... ON CONFLICT (...) DO (UPDATE SET ...)/(NOTHING)&#xff09; 语…

作者头像 李华