当前位置: 首页 > news >正文

CommunityToolkit.Mvvm 重构激光直写控制软件

使用 CommunityToolkit.Mvvm 库重新设计激光直写控制软件的框架,展示现代 MVVM 实现方式。

一、项目结构

LaserDirectWriteApp/
├── Models/
│   ├── LaserParameters.cs
│   ├── MotionParameters.cs
│   └── SystemStatus.cs
├── ViewModels/
│   ├── MainViewModel.cs
│   ├── LaserControlViewModel.cs
│   ├── MotionControlViewModel.cs
│   └── PreviewViewModel.cs
├── Views/
│   ├── MainWindow.xaml
│   ├── LaserControlView.xaml
│   ├── MotionControlView.xaml
│   └── PreviewView.xaml
├── Services/
│   ├── ILaserService.cs
│   ├── IMotionService.cs
│   ├── LaserService.cs
│   └── MotionService.cs
├── Converters/
│   └── BooleanToStatusConverter.cs
└── App.xaml

 

二、核心实现

1. 安装必要包

dotnet add package CommunityToolkit.Mvvm
dotnet add package Microsoft.Extensions.DependencyInjection

2. 应用入口 (App.xaml.cs)

using Microsoft.Extensions.DependencyInjection;
using CommunityToolkit.Mvvm.DependencyInjection;public partial class App : Application
{public App(){// 配置依赖注入Ioc.Default.ConfigureServices(new ServiceCollection().AddSingleton<ILaserService, LaserService>().AddSingleton<IMotionService, MotionService>().AddTransient<MainViewModel>().AddTransient<LaserControlViewModel>().AddTransient<MotionControlViewModel>().AddTransient<PreviewViewModel>().BuildServiceProvider());}protected override void OnStartup(StartupEventArgs e){base.OnStartup(e);var mainWindow = new MainWindow{DataContext = Ioc.Default.GetRequiredService<MainViewModel>()};mainWindow.Show();}
}

3. 主视图模型 (MainViewModel.cs)

using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using CommunityToolkit.Mvvm.Messaging;public partial class MainViewModel : ObservableObject
{private readonly ILaserService _laserService;private readonly IMotionService _motionService;[ObservableProperty]private string _statusMessage = "系统就绪";[ObservableProperty][NotifyPropertyChangedFor(nameof(IsDisconnected))]private bool _isConnected;public bool IsDisconnected => !IsConnected;public MainViewModel(ILaserService laserService, IMotionService motionService){_laserService = laserService;_motionService = motionService;// 订阅设备状态消息WeakReferenceMessenger.Default.Register<DeviceStatusMessage>(this, (r, m) =>{StatusMessage = m.Message;});}[RelayCommand]private async Task ConnectAsync(){try{WeakReferenceMessenger.Default.Send(new DeviceStatusMessage("正在连接设备..."));await Task.WhenAll(Task.Run(() => _motionService.Connect()),Task.Run(() => _laserService.Connect()));IsConnected = true;WeakReferenceMessenger.Default.Send(new DeviceStatusMessage("设备连接成功"));}catch (Exception ex){WeakReferenceMessenger.Default.Send(new DeviceStatusMessage($"连接失败: {ex.Message}"));}}[RelayCommand(CanExecute = nameof(IsConnected))]private void Disconnect(){try{WeakReferenceMessenger.Default.Send(new DeviceStatusMessage("正在断开设备..."));_laserService.Disconnect();_motionService.Disconnect();IsConnected = false;WeakReferenceMessenger.Default.Send(new DeviceStatusMessage("设备已断开"));}catch (Exception ex){WeakReferenceMessenger.Default.Send(new DeviceStatusMessage($"断开失败: {ex.Message}"));}}[RelayCommand]private void Exit(){if (IsConnected) Disconnect();Application.Current.Shutdown();}
}public record DeviceStatusMessage(string Message);

4. 激光控制视图模型 (LaserControlViewModel.cs)

public partial class LaserControlViewModel : ObservableObject
{private readonly ILaserService _laserService;[ObservableProperty]private LaserParameters _parameters = new();public LaserControlViewModel(ILaserService laserService){_laserService = laserService;// 初始化默认值Parameters = new LaserParameters{Power = 30,Frequency = 1000,PulseWidth = 100};}[RelayCommand]private void ToggleLaser(){try{_laserService.SetEnabled(Parameters.IsEnabled);WeakReferenceMessenger.Default.Send(new DeviceStatusMessage($"激光器已{(Parameters.IsEnabled ? "开启" : "关闭"}"));}catch (Exception ex){WeakReferenceMessenger.Default.Send(new DeviceStatusMessage($"激光控制失败: {ex.Message}"));}}[RelayCommand]private void ApplySettings(){try{_laserService.SetPower(Parameters.Power);_laserService.SetFrequency(Parameters.Frequency);_laserService.SetPulseWidth(Parameters.PulseWidth);WeakReferenceMessenger.Default.Send(new DeviceStatusMessage("激光参数已更新"));}catch (Exception ex){WeakReferenceMessenger.Default.Send(new DeviceStatusMessage($"参数设置失败: {ex.Message}"));}}
}

5. 运动控制视图模型 (MotionControlViewModel.cs)

public partial class MotionControlViewModel : ObservableObject
{private readonly IMotionService _motionService;[ObservableProperty]private MotionParameters _parameters = new();public MotionControlViewModel(IMotionService motionService){_motionService = motionService;// 订阅位置更新_motionService.PositionUpdated += OnPositionUpdated;}private void OnPositionUpdated(object? sender, PositionUpdatedEventArgs e){Parameters.XPosition = e.X;Parameters.YPosition = e.Y;Parameters.ZPosition = e.Z;}[RelayCommand(CanExecute = nameof(CanMove))]private async Task MoveAsync(){try{await _motionService.MoveTo(Parameters.XTarget,Parameters.YTarget,Parameters.ZTarget);}catch (Exception ex){WeakReferenceMessenger.Default.Send(new DeviceStatusMessage($"移动失败: {ex.Message}"));}}private bool CanMove() => !_motionService.IsMoving;[RelayCommand]private async Task HomeAsync(){try{await _motionService.Home();WeakReferenceMessenger.Default.Send(new DeviceStatusMessage("已回原点"));}catch (Exception ex){WeakReferenceMessenger.Default.Send(new DeviceStatusMessage($"回原点失败: {ex.Message}"));}}
}

6. 主窗口视图 (MainWindow.xaml)

<Window x:Class="LaserDirectWriteApp.Views.MainWindow"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"xmlns:d="http://schemas.microsoft.com/expression/blend/2008"xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"xmlns:local="clr-namespace:LaserDirectWriteApp.Views"mc:Ignorable="d"Title="激光直写控制系统" Height="800" Width="1200"><DockPanel><!-- 顶部菜单 --><Menu DockPanel.Dock="Top"><MenuItem Header="文件"><MenuItem Command="{Binding ExitCommand}" Header="退出"/></MenuItem><MenuItem Header="设备"><MenuItem Command="{Binding ConnectCommand}" Header="连接"/><MenuItem Command="{Binding DisconnectCommand}" Header="断开" IsEnabled="{Binding IsConnected}"/></MenuItem></Menu><!-- 状态栏 --><StatusBar DockPanel.Dock="Bottom"><StatusBarItem><TextBlock Text="{Binding StatusMessage}"/></StatusBarItem></StatusBar><!-- 主内容区 --><TabControl><TabItem Header="激光控制"><local:LaserControlView DataContext="{Binding Source={x:Static Ioc.Default}, Path=GetRequiredService{LaserControlViewModel}}"/></TabItem><TabItem Header="运动控制"><local:MotionControlView DataContext="{Binding Source={x:Static Ioc.Default}, Path=GetRequiredService{MotionControlViewModel}}"/></TabItem><TabItem Header="预览"><local:PreviewView DataContext="{Binding Source={x:Static Ioc.Default}, Path=GetRequiredService{PreviewViewModel}}"/></TabItem></TabControl></DockPanel>
</Window>

三、CommunityToolkit.Mvvm 优势体现

  1. 极简代码:使用 [ObservableProperty] 和 [RelayCommand] 大幅减少样板代码

    • 传统方式需要 20+ 行代码的属性现在只需 1 行

    • 命令实现从 10+ 行减少到 1 行属性

  2. 类型安全:源码生成器保证编译时类型检查

[ObservableProperty]
private string _name; // 自动生成 Name 属性,带通知功能

现代化异步支持

[RelayCommand]
private async Task LoadDataAsync()
{// 自动处理异步操作和异常
}

弱引用消息:避免内存泄漏

WeakReferenceMessenger.Default.Register<MyMessage>(this, (r, m) => { });

依赖注入集成

// 配置
Ioc.Default.ConfigureServices(services);// 使用
var vm = Ioc.Default.GetRequiredService<MyViewModel>();

四、扩展建议

  1. 添加验证:结合 DataAnnotations 实现属性验证

[ObservableProperty]
[Required(ErrorMessage = "功率不能为空")]
[Range(0, 100, ErrorMessage = "功率必须在0-100之间")]
private double _power;

使用记录类型:为消息定义不可变模型

public record PositionMessage(double X, double Y, double Z);

添加单元测试:利用轻量级特性简化测试

var vm = new LaserControlViewModel(mockLaserService);
vm.ToggleLaserCommand.Execute(null);
mockLaserService.Verify(x => x.SetEnabled(true));

这个实现展示了如何使用 CommunityToolkit.Mvvm 构建现代化、高性能的激光直写控制软件,相比传统 MVVM 实现代码量减少约 40%,同时提高了可维护性和类型安全性。

相关文章:

  • 公司内部网站创建百度广告一天多少钱
  • 有没有可以做网站动图的软件友情链接在线观看
  • 石狮网站设计公司网络推广seo
  • 公司做个网站好还是做公众号好电商网站网址
  • 学建设网站首页百度总部电话
  • 武汉大型网站制作搜狗关键词排名查询
  • Jenkins 常用定时构建脚本
  • 电商导购app平台的缓存策略与性能优化方案:架构师的实践经验
  • 将Python Tkinter程序转换为手机可运行的Web应用 - 详细教程
  • 激光束修复手机屏任意层不良区域,实现液晶线路激光修复原理
  • wordpress Contact Form 7表单插件设置使用教程
  • Hoare逻辑与分离逻辑:从程序验证到内存推理的演进
  • 智能光学计算成像技术与应用
  • 鸿蒙Next仓颉开发语言中的数据类型总结分享
  • 初识Tomcat
  • 6、做中学 | 三年级下期 Golang值类型相互转换
  • 好用的图标库和字体库
  • 《中国电信运营商骨干网:历史、现状与未来演进》系列 第五篇:新玩家入局——中国广电CBNNET如何构建全国一张网?
  • 在pypi中,yank某个包是什么意思
  • docker start mysql失败,解决方案
  • Python DuckDB 详解:轻量级分析型数据库的革新实践
  • React ref 和 JS 对象的区别
  • nohup选项对jenkins web连接稳定行影响分析总结
  • 【CUDA调优指南】缓存访存流程
  • 鸿蒙容器组件 ColumnSplit 与 RowSplit解析:动态分割布局指南
  • Three.js项目实战:从零搭建小米SU7三维汽车