Files
CapMachine/CapMachine.Wpf/ViewModels/ZlgCanDriveConfigViewModel.cs
2026-02-06 12:34:34 +08:00

2204 lines
90 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using AutoMapper;
using CapMachine.Core;
using CapMachine.Model.CANLIN;
using CapMachine.Wpf.CanDrive;
using CapMachine.Wpf.Dtos;
using CapMachine.Wpf.Services;
using CapMachine.Wpf.Views;
using ImTools;
using Microsoft.Win32;
using Prism.Commands;
using Prism.Events;
using Prism.Regions;
using Prism.Services.Dialogs;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.IO;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using static CapMachine.Wpf.Models.ComEnum;
namespace CapMachine.Wpf.ViewModels
{
/// <summary>
/// ZLG CAN/CANFD 合并配置 ViewModel模式切换单选
/// </summary>
public class ZlgCanDriveConfigViewModel : NavigationViewModel
{
/// <summary>
/// 构造函数。
/// </summary>
public ZlgCanDriveConfigViewModel(IDialogService dialogService, IFreeSql freeSql,
IEventAggregator eventAggregator, IRegionManager regionManager, SysRunService sysRunService,
ComActionService comActionService, ILogService logService, LogicRuleService logicRuleService,
ConfigService configService, ZlgCanDriveService zlgCanDriveService, ZlgLinDriveService zlgLinDriveService,
IMapper mapper)
{
DialogService = dialogService;
FreeSql = freeSql;
EventAggregator = eventAggregator;
RegionManager = regionManager;
SysRunService = sysRunService;
ComActionService = comActionService;
LogService = logService;
LogicRuleService = logicRuleService;
ConfigService = configService;
ZlgCanDriveService = zlgCanDriveService;
ZlgLinDriveService = zlgLinDriveService;
Mapper = mapper;
SelectedMode = ZlgCanMode.Can;
ArbBaudRateCbxItems = new ObservableCollection<CbxItems>()
{
new CbxItems(){ Key="10000",Text="10 Kbps"},
new CbxItems(){ Key="20000",Text="20 Kbps"},
new CbxItems(){ Key="33000",Text="33 Kbps"},
new CbxItems(){ Key="50000",Text="50 Kbps"},
new CbxItems(){ Key="83000",Text="83 Kbps"},
new CbxItems(){ Key="100000",Text="100 Kbps"},
new CbxItems(){ Key="125000",Text="125 Kbps"},
new CbxItems(){ Key="150000",Text="150 Kbps"},
new CbxItems(){ Key="200000",Text="200 Kbps"},
new CbxItems(){ Key="250000",Text="250 Kbps"},
new CbxItems(){ Key="300000",Text="300 Kbps"},
new CbxItems(){ Key="400000",Text="400 Kbps"},
new CbxItems(){ Key="500000",Text="500 Kbps"},
new CbxItems(){ Key="666000",Text="666 Kbps"},
new CbxItems(){ Key="800000",Text="800 Kbps"},
new CbxItems(){ Key="1000000",Text="1.0 Mbps"},
};
DataBaudRateCbxItems = new ObservableCollection<CbxItems>()
{
new CbxItems(){ Key="100000",Text="100 Kbps"},
new CbxItems(){ Key="125000",Text="125 Kbps"},
new CbxItems(){ Key="200000",Text="200 Kbps"},
new CbxItems(){ Key="250000",Text="250 Kbps"},
new CbxItems(){ Key="400000",Text="400 Kbps"},
new CbxItems(){ Key="500000",Text="500 Kbps"},
new CbxItems(){ Key="666000",Text="666 Kbps"},
new CbxItems(){ Key="800000",Text="800 Kbps"},
new CbxItems(){ Key="1000000",Text="1.0 Mbps"},
new CbxItems(){ Key="1500000",Text="1.5 Mbps"},
new CbxItems(){ Key="2000000",Text="2.0 Mbps"},
new CbxItems(){ Key="3000000",Text="3.0 Mbps"},
new CbxItems(){ Key="4000000",Text="4.0 Mbps"},
new CbxItems(){ Key="5000000",Text="5.0 Mbps"},
new CbxItems(){ Key="6700000",Text="6.7 Mbps"},
new CbxItems(){ Key="8000000",Text="8.0 Mbps"},
new CbxItems(){ Key="10000000",Text="10.0 Mbps"},
};
InitWriteRuleCbx();
InitLoadCanConfigPro();
}
private void InitWriteRuleCbx()
{
WriteRuleCbxItems = new ObservableCollection<CbxItems>();
foreach (var itemRule in LogicRuleService.LogicRuleDtos)
{
WriteRuleCbxItems.Add(new CbxItems()
{
Key = itemRule.Id.ToString(),
Text = itemRule.Name
});
}
}
private void OpenRwDialog()
{
try
{
if (SelectCanLinConfigPro == null)
{
MessageBox.Show("选中CAN配置名称后再操作", "提示", MessageBoxButton.OK, MessageBoxImage.Hand);
return;
}
var writeClones = new ObservableCollection<CanLinRWConfigDto>(
(ListWriteCanLinRWConfigDto ?? new ObservableCollection<CanLinRWConfigDto>())
.Select(CloneRwDto));
foreach (var item in writeClones)
{
item.RWInfo = RW.Write;
}
var readClones = new ObservableCollection<CanLinRWConfigDto>(
(ListReadCanLinRWConfigDto ?? new ObservableCollection<CanLinRWConfigDto>())
.Select(CloneRwDto));
foreach (var item in readClones)
{
item.RWInfo = RW.Read;
}
var candidates = new ObservableCollection<DialogZlgCanLinRwConfigViewModel.SignalCandidate>();
if (ListCanDbcModel != null)
{
foreach (var sig in ListCanDbcModel)
{
candidates.Add(new DialogZlgCanLinRwConfigViewModel.SignalCandidate
{
MsgName = sig.MsgName,
SignalName = sig.SignalName,
Name = sig.Name,
Desc = sig.SignalDesc,
});
}
}
var pars = new DialogParameters
{
{ "Title", "读写设置" },
{ "CanLinConfigProId", SelectCanLinConfigPro.Id },
{ "IsEditable", IsRwEditable },
{ "WriteConfigs", writeClones },
{ "ReadConfigs", readClones },
{ "SignalCandidates", candidates },
};
DialogService.ShowDialog(nameof(DialogZlgCanLinRwConfigView), pars, r =>
{
if (r.Result == ButtonResult.OK)
{
ReloadCurrentConfigPro();
OpTip = "读写设置已保存";
}
});
}
catch (Exception ex)
{
LogService.Error($"ZLG 打开读写设置弹窗失败:{ex}");
MessageBox.Show(ex.Message, "错误", MessageBoxButton.OK, MessageBoxImage.Error);
}
}
private static CanLinRWConfigDto CloneRwDto(CanLinRWConfigDto src)
{
return new CanLinRWConfigDto
{
Id = src.Id,
RWInfo = src.RWInfo,
Name = src.Name,
MsgFrameName = src.MsgFrameName,
SignalName = src.SignalName,
DefautValue = src.DefautValue,
LogicRuleId = src.LogicRuleId,
LogicRuleDto = src.LogicRuleDto,
};
}
/// <summary>
/// Dialog 服务。
/// </summary>
public IDialogService DialogService { get; }
/// <summary>
/// FreeSql。
/// </summary>
public IFreeSql FreeSql { get; }
/// <summary>
/// 事件聚合。
/// </summary>
public IEventAggregator EventAggregator { get; }
/// <summary>
/// 区域导航。
/// </summary>
public IRegionManager RegionManager { get; }
/// <summary>
/// 系统运行服务。
/// </summary>
public SysRunService SysRunService { get; }
/// <summary>
/// 通信互斥控制。
/// </summary>
public ComActionService ComActionService { get; }
/// <summary>
/// 日志。
/// </summary>
public ILogService LogService { get; }
/// <summary>
/// 逻辑规则服务。
/// </summary>
public LogicRuleService LogicRuleService { get; }
/// <summary>
/// 配置服务。
/// </summary>
public ConfigService ConfigService { get; }
/// <summary>
/// ZLG CAN 服务。
/// </summary>
public ZlgCanDriveService ZlgCanDriveService { get; }
/// <summary>
/// ZLG LIN 服务(用于互斥判断)。
/// </summary>
public ZlgLinDriveService ZlgLinDriveService { get; }
/// <summary>
/// Mapper。
/// </summary>
public IMapper Mapper { get; }
private ObservableCollection<CbxItems> _arbBaudRateCbxItems = new ObservableCollection<CbxItems>();
/// <summary>
/// 仲裁波特率下拉项bps
/// </summary>
public ObservableCollection<CbxItems> ArbBaudRateCbxItems
{
get { return _arbBaudRateCbxItems; }
set { _arbBaudRateCbxItems = value; RaisePropertyChanged(); }
}
private ObservableCollection<CbxItems> _dataBaudRateCbxItems = new ObservableCollection<CbxItems>();
/// <summary>
/// 数据波特率下拉项bps
/// </summary>
public ObservableCollection<CbxItems> DataBaudRateCbxItems
{
get { return _dataBaudRateCbxItems; }
set { _dataBaudRateCbxItems = value; RaisePropertyChanged(); }
}
private List<CanLinConfigPro> _canLinConfigPros = new List<CanLinConfigPro>();
private ObservableCollection<CbxItems> _writeRuleCbxItems = new ObservableCollection<CbxItems>();
public ObservableCollection<CbxItems> WriteRuleCbxItems
{
get { return _writeRuleCbxItems; }
set { _writeRuleCbxItems = value; RaisePropertyChanged(); }
}
private ObservableCollection<CanLinRWConfigDto> _listWriteCanLinRWConfigDto = new ObservableCollection<CanLinRWConfigDto>();
public ObservableCollection<CanLinRWConfigDto> ListWriteCanLinRWConfigDto
{
get { return _listWriteCanLinRWConfigDto; }
set { _listWriteCanLinRWConfigDto = value; RaisePropertyChanged(); }
}
private ObservableCollection<CanLinRWConfigDto> _listReadCanLinRWConfigDto = new ObservableCollection<CanLinRWConfigDto>();
public ObservableCollection<CanLinRWConfigDto> ListReadCanLinRWConfigDto
{
get { return _listReadCanLinRWConfigDto; }
set { _listReadCanLinRWConfigDto = value; RaisePropertyChanged(); }
}
private CanLinRWConfigDto? SelectedWriteCanLinRWConfigDto { get; set; }
private CanLinRWConfigDto? SelectedReadCanLinRWConfigDto { get; set; }
private string? _opTip;
/// <summary>
/// 操作提示(用于 UI 状态展示)。
/// </summary>
public string? OpTip
{
get { return _opTip; }
set { _opTip = value; RaisePropertyChanged(); }
}
private string? _lastError;
/// <summary>
/// 最近一次错误信息(用于 UI 状态展示)。
/// </summary>
public string? LastError
{
get { return _lastError; }
set { _lastError = value; RaisePropertyChanged(); }
}
private bool _isCanConfigProActive;
/// <summary>
/// 当前配置程序是否已激活(对齐图莫斯 Active 语义)。
/// 激活后禁止切换配置程序。
/// </summary>
public bool IsCanConfigProActive
{
get { return _isCanConfigProActive; }
set
{
_isCanConfigProActive = value;
RaisePropertyChanged();
RaisePropertyChanged(nameof(IsRwEditable));
}
}
public bool IsRwEditable
{
get { return !IsCanConfigProActive; }
}
private bool _isCANConfigDatagridActive = true;
/// <summary>
/// 配置程序 DataGrid 是否可操作(与 IsCanConfigProActive 取反)。
/// </summary>
public bool IsCANConfigDatagridActive
{
get { return _isCANConfigDatagridActive; }
set { _isCANConfigDatagridActive = value; RaisePropertyChanged(); }
}
private ZlgCanMode _selectedMode;
/// <summary>
/// 模式选择CAN/CANFD单选
/// </summary>
public ZlgCanMode SelectedMode
{
get { return _selectedMode; }
set
{
// 打开状态下不允许切换模式,避免驱动状态错乱。
if (ZlgCanDriveService.OpenState && _selectedMode != value)
{
MessageBox.Show("请先关闭 CAN 后再切换 CAN/CANFD 模式", "提示", MessageBoxButton.OK, MessageBoxImage.Hand);
RaisePropertyChanged(nameof(SelectedModeKey));
return;
}
_selectedMode = value;
RaisePropertyChanged();
RaisePropertyChanged(nameof(SelectedModeKey));
RaisePropertyChanged(nameof(IsCanMode));
RaisePropertyChanged(nameof(IsCanFdMode));
RaisePropertyChanged(nameof(DbcPathTitle));
RaisePropertyChanged(nameof(ConnectButtonText));
RaisePropertyChanged(nameof(CloseButtonText));
RaisePropertyChanged(nameof(CurrentDbcPath));
RaisePropertyChanged(nameof(CurrentCycle));
RaisePropertyChanged(nameof(CurrentSchEnable));
RaisePropertyChanged(nameof(CurrentArbBaudRate));
RaisePropertyChanged(nameof(CurrentDataBaudRate));
RaisePropertyChanged(nameof(CurrentISOEnable));
RaisePropertyChanged(nameof(CurrentResEnable));
RaisePropertyChanged(nameof(BaudRateTitle));
RaisePropertyChanged(nameof(DataBaudRateTitle));
ZlgCanDriveService.Mode = value;
// 当用户手动切换 CAN/CANFD 时,如果当前配置缺少对应扩展 DTO需要先生成默认 DTO
// 否则界面控件无法编辑setter 会因 DTO 为空直接 return
if (SelectCanLinConfigPro != null)
{
if (value == ZlgCanMode.Can)
{
if (SelectedCANConfigExdDto == null)
{
SelectedCANConfigExdDto = new CANConfigExdDto()
{
Id = 0,
BaudRate = 500000,
DbcPath = string.Empty,
Cycle = 100,
SchEnable = false,
};
}
}
else
{
if (SelectedCANFdConfigExdDto == null)
{
SelectedCANFdConfigExdDto = new CANFdConfigExdDto()
{
Id = 0,
ArbBaudRate = 500000,
DataBaudRate = 2000000,
ISOEnable = true,
ResEnable = false,
DbcPath = string.Empty,
Cycle = 100,
SchEnable = false,
};
}
}
}
// 切换模式后,为避免界面仍显示旧的 DBC 信号列表,清空信号集合。
// 配置程序列表不应随模式切换而过滤/刷新。
ListCanDbcModel = new ObservableCollection<CanDbcModel>();
}
}
private DelegateCommand<object>? _writeGridSelectionChangedCmd;
public DelegateCommand<object> WriteGridSelectionChangedCmd
{
get
{
if (_writeGridSelectionChangedCmd == null)
{
_writeGridSelectionChangedCmd = new DelegateCommand<object>(WriteGridSelectionChangedCmdMethod);
}
return _writeGridSelectionChangedCmd;
}
}
private void WriteGridSelectionChangedCmdMethod(object par)
{
if (par is CanLinRWConfigDto dto)
{
SelectedWriteCanLinRWConfigDto = dto;
}
}
private DelegateCommand<object>? _readGridSelectionChangedCmd;
public DelegateCommand<object> ReadGridSelectionChangedCmd
{
get
{
if (_readGridSelectionChangedCmd == null)
{
_readGridSelectionChangedCmd = new DelegateCommand<object>(ReadGridSelectionChangedCmdMethod);
}
return _readGridSelectionChangedCmd;
}
}
private void ReadGridSelectionChangedCmdMethod(object par)
{
if (par is CanLinRWConfigDto dto)
{
SelectedReadCanLinRWConfigDto = dto;
}
}
private DelegateCommand<string>? _writeCmd;
public DelegateCommand<string> WriteCmd
{
get
{
if (_writeCmd == null)
{
_writeCmd = new DelegateCommand<string>(WriteCmdMethod);
}
return _writeCmd;
}
}
private void WriteCmdMethod(string par)
{
if (SelectCanLinConfigPro == null)
{
MessageBox.Show("选中CAN配置名称后再操作", "提示", MessageBoxButton.OK, MessageBoxImage.Hand);
return;
}
if (IsCanConfigProActive)
{
MessageBox.Show("当前配置已激活,请先取消激活后再修改写入配置", "提示", MessageBoxButton.OK, MessageBoxImage.Hand);
return;
}
switch (par)
{
case "Edit":
foreach (var item in ListWriteCanLinRWConfigDto)
{
FreeSql.Update<CanLinRWConfig>(item.Id)
.Set(a => a.Name, item.Name)
.Set(a => a.LogicRuleId, item.LogicRuleId)
.Set(a => a.DefautValue, item.DefautValue)
.ExecuteAffrows();
}
ReloadCurrentConfigPro();
OpTip = "写入配置已保存";
break;
case "Delete":
if (SelectedWriteCanLinRWConfigDto == null)
{
MessageBox.Show("请选中写入列表中的一行后再删除", "提示", MessageBoxButton.OK, MessageBoxImage.Hand);
return;
}
FreeSql.Delete<CanLinRWConfig>(SelectedWriteCanLinRWConfigDto.Id).ExecuteAffrows();
ReloadCurrentConfigPro();
OpTip = "写入配置已删除";
break;
}
}
private DelegateCommand<string>? _readCmd;
public DelegateCommand<string> ReadCmd
{
get
{
if (_readCmd == null)
{
_readCmd = new DelegateCommand<string>(ReadCmdMethod);
}
return _readCmd;
}
}
private void ReadCmdMethod(string par)
{
if (SelectCanLinConfigPro == null)
{
MessageBox.Show("选中CAN配置名称后再操作", "提示", MessageBoxButton.OK, MessageBoxImage.Hand);
return;
}
if (IsCanConfigProActive)
{
MessageBox.Show("当前配置已激活,请先取消激活后再修改读取配置", "提示", MessageBoxButton.OK, MessageBoxImage.Hand);
return;
}
switch (par)
{
case "Edit":
foreach (var item in ListReadCanLinRWConfigDto)
{
FreeSql.Update<CanLinRWConfig>(item.Id)
.Set(a => a.Name, item.Name)
.Set(a => a.DefautValue, item.DefautValue)
.ExecuteAffrows();
}
ReloadCurrentConfigPro();
OpTip = "读取配置已保存";
break;
case "Delete":
if (SelectedReadCanLinRWConfigDto == null)
{
MessageBox.Show("请选中读取列表中的一行后再删除", "提示", MessageBoxButton.OK, MessageBoxImage.Hand);
return;
}
FreeSql.Delete<CanLinRWConfig>(SelectedReadCanLinRWConfigDto.Id).ExecuteAffrows();
ReloadCurrentConfigPro();
OpTip = "读取配置已删除";
break;
}
}
/// <summary>
/// 连接按钮文字(对齐 Toomoss 风格)。
/// </summary>
public string ConnectButtonText
{
get { return SelectedMode == ZlgCanMode.Can ? "连接CAN" : "连接CANFD"; }
}
/// <summary>
/// 当前是否为 CANFD 模式(用于 UI 启用/禁用某些仅 CANFD 支持的参数)。
/// </summary>
public bool IsCanFdMode
{
get { return SelectedMode == ZlgCanMode.CanFd; }
}
/// <summary>
/// 当前是否为 CAN 模式(用于 UI 启用/禁用某些仅 CANFD 支持的参数)。
/// </summary>
public bool IsCanMode
{
get { return SelectedMode == ZlgCanMode.Can; }
}
/// <summary>
/// 波特率标题CAN 为“波特率”CANFD 为“仲裁波特率”。
/// </summary>
public string BaudRateTitle
{
get { return SelectedMode == ZlgCanMode.Can ? "波特率" : "仲裁波特率"; }
}
/// <summary>
/// 数据波特率标题:仅 CANFD 有意义。
/// </summary>
public string DataBaudRateTitle
{
get { return "数据波特率"; }
}
/// <summary>
/// 关闭按钮文字(对齐 Toomoss 风格)。
/// </summary>
public string CloseButtonText
{
get { return SelectedMode == ZlgCanMode.Can ? "关闭CAN" : "关闭CANFD"; }
}
/// <summary>
/// 绑定用:模式 KeyCan/CanFd
/// </summary>
public string SelectedModeKey
{
get { return SelectedMode == ZlgCanMode.Can ? "Can" : "CanFd"; }
set
{
if (ZlgCanDriveService.OpenState)
{
MessageBox.Show("请先关闭 CAN 后再切换 CAN/CANFD 模式", "提示", MessageBoxButton.OK, MessageBoxImage.Hand);
RaisePropertyChanged();
return;
}
if (string.Equals(value, "Can", StringComparison.OrdinalIgnoreCase))
{
SelectedMode = ZlgCanMode.Can;
return;
}
if (string.Equals(value, "CanFd", StringComparison.OrdinalIgnoreCase) || string.Equals(value, "CanFD", StringComparison.OrdinalIgnoreCase))
{
SelectedMode = ZlgCanMode.CanFd;
return;
}
}
}
/// <summary>
/// DBC 路径标题。
/// </summary>
public string DbcPathTitle
{
get { return SelectedMode == ZlgCanMode.Can ? "CAN-DBC文件路径:" : "CANFD-DBC文件路径:"; }
}
private ObservableCollection<CanLinConfigPro>? _listCanLinConfigPro;
/// <summary>
/// 配置程序集合。
/// </summary>
public ObservableCollection<CanLinConfigPro>? ListCanLinConfigPro
{
get { return _listCanLinConfigPro; }
set { _listCanLinConfigPro = value; RaisePropertyChanged(); }
}
/// <summary>
/// 选中的配置程序。
/// </summary>
private CanLinConfigPro? _selectCanLinConfigPro;
/// <summary>
/// 选中的配置程序。
/// </summary>
public CanLinConfigPro? SelectCanLinConfigPro
{
get { return _selectCanLinConfigPro; }
set
{
_selectCanLinConfigPro = value;
RaisePropertyChanged();
}
}
private ObservableCollection<CanDbcModel>? _listCanDbcModel;
/// <summary>
/// DBC 信号集合。
/// </summary>
public ObservableCollection<CanDbcModel>? ListCanDbcModel
{
get { return _listCanDbcModel; }
set { _listCanDbcModel = value; RaisePropertyChanged(); }
}
/// <summary>
/// 当前选中的 DBC 信号。
/// </summary>
public CanDbcModel? SelectedCanDbcModel
{
get { return _selectedCanDbcModel; }
set { _selectedCanDbcModel = value; RaisePropertyChanged(); }
}
private CanDbcModel? _selectedCanDbcModel;
private CANConfigExdDto? _selectedCANConfigExdDto;
/// <summary>
/// CAN 配置 DTO。
/// </summary>
public CANConfigExdDto? SelectedCANConfigExdDto
{
get { return _selectedCANConfigExdDto; }
set { _selectedCANConfigExdDto = value; RaisePropertyChanged(); }
}
private CANFdConfigExdDto? _selectedCANFdConfigExdDto;
/// <summary>
/// CANFD 配置 DTO。
/// </summary>
public CANFdConfigExdDto? SelectedCANFdConfigExdDto
{
get { return _selectedCANFdConfigExdDto; }
set { _selectedCANFdConfigExdDto = value; RaisePropertyChanged(); }
}
private void InitLoadCanConfigPro()
{
_canLinConfigPros = FreeSql.Select<CanLinConfigPro>()
.Where(a => a.CANLINInfo == CANLIN.CAN || a.CANLINInfo == CANLIN.CANFD)
.Include(a => a.CANConfigExd)
.Include(a => a.CANFdConfigExd)
.IncludeMany(a => a.CanLinConfigContents, then => then.Include(b => b.LogicRule))
.IncludeMany(a => a.CanScheduleConfigs)
.IncludeMany(a => a.CanFdScheduleConfigs)
.ToList();
ListCanLinConfigPro = new ObservableCollection<CanLinConfigPro>(_canLinConfigPros);
}
/// <summary>
/// 同步选中的配置。
/// </summary>
private void SyncSelectedConfig()
{
if (SelectCanLinConfigPro == null)
{
return;
}
// 选中配置程序后,模式应跟随该配置自身的 CANLINInfo避免“列表全量但右侧模式不匹配”。
var proMode = SelectCanLinConfigPro.CANLINInfo == CANLIN.CAN ? ZlgCanMode.Can : ZlgCanMode.CanFd;
if (SelectedMode != proMode)
{
SelectedMode = proMode;
}
// 同时映射两套配置(如不存在则为 null这样用户可以在 UI 上切换模式后再保存。
SelectedCANConfigExdDto = SelectCanLinConfigPro.CANConfigExd != null
? Mapper.Map<CANConfigExdDto>(SelectCanLinConfigPro.CANConfigExd)
: null;
SelectedCANFdConfigExdDto = SelectCanLinConfigPro.CANFdConfigExd != null
? Mapper.Map<CANFdConfigExdDto>(SelectCanLinConfigPro.CANFdConfigExd)
: null;
RaisePropertyChanged(nameof(CurrentDbcPath));
RaisePropertyChanged(nameof(CurrentCycle));
RaisePropertyChanged(nameof(CurrentSchEnable));
RaisePropertyChanged(nameof(CurrentArbBaudRate));
RaisePropertyChanged(nameof(CurrentDataBaudRate));
RaisePropertyChanged(nameof(CurrentISOEnable));
RaisePropertyChanged(nameof(CurrentResEnable));
RaisePropertyChanged(nameof(CanBaudRate));
RaisePropertyChanged(nameof(CanFdArbBaudRate));
RaisePropertyChanged(nameof(CanFdDataBaudRate));
BuildAndLoadCmdDataToDrive();
var writeData = SelectCanLinConfigPro.CanLinConfigContents?.Where(a => a.RWInfo == RW.Write).ToList() ?? new List<CanLinRWConfig>();
ListWriteCanLinRWConfigDto = new ObservableCollection<CanLinRWConfigDto>(Mapper.Map<List<CanLinRWConfigDto>>(writeData));
var readData = SelectCanLinConfigPro.CanLinConfigContents?.Where(a => a.RWInfo == RW.Read).ToList() ?? new List<CanLinRWConfig>();
ListReadCanLinRWConfigDto = new ObservableCollection<CanLinRWConfigDto>(Mapper.Map<List<CanLinRWConfigDto>>(readData));
// 调度表(按模式)
if (SelectedMode == ZlgCanMode.Can)
{
if (SelectCanLinConfigPro.CanScheduleConfigs != null && SelectCanLinConfigPro.CanScheduleConfigs.Count > 0)
{
ListCANScheduleConfigDto = new ObservableCollection<CANScheduleConfigDto>(Mapper.Map<List<CANScheduleConfigDto>>(SelectCanLinConfigPro.CanScheduleConfigs));
}
else
{
ListCANScheduleConfigDto = new ObservableCollection<CANScheduleConfigDto>();
}
RaisePropertyChanged(nameof(ListCANScheduleConfigDto));
}
else
{
if (SelectCanLinConfigPro.CanFdScheduleConfigs != null && SelectCanLinConfigPro.CanFdScheduleConfigs.Count > 0)
{
ListCANFdScheduleConfigDto = new ObservableCollection<CANFdScheduleConfigDto>(Mapper.Map<List<CANFdScheduleConfigDto>>(SelectCanLinConfigPro.CanFdScheduleConfigs));
}
else
{
ListCANFdScheduleConfigDto = new ObservableCollection<CANFdScheduleConfigDto>();
}
RaisePropertyChanged(nameof(ListCANFdScheduleConfigDto));
}
ResetAndTryLoadDbcSignalsForSelectedConfig();
}
/// <summary>
/// 切换配置程序时重置并尝试加载当前配置对应的 DBC 信号集合。
/// </summary>
private void ResetAndTryLoadDbcSignalsForSelectedConfig()
{
SelectedCanDbcModel = null;
// 未连接时:信号集合应以当前配置的 DBC 为准(或为空),禁止沿用上一个配置的信号列表。
if (!ZlgCanDriveService.OpenState)
{
if (string.IsNullOrWhiteSpace(CurrentDbcPath))
{
ListCanDbcModel = new ObservableCollection<CanDbcModel>();
return;
}
try
{
ListCanDbcModel = ZlgCanDriveService.StartDbc(CurrentDbcPath);
MatchSeletedAndCanDbcModel();
}
catch (Exception ex)
{
ListCanDbcModel = new ObservableCollection<CanDbcModel>();
OpTip = "DBC 解析失败";
LogService.Warn($"切换配置程序时解析 DBC 失败:{CurrentDbcPath}{ex.Message}");
}
return;
}
// 已连接时:禁止切换配置程序,理论上不会执行到这里;保底清空,避免 UI 残留。
ListCanDbcModel = new ObservableCollection<CanDbcModel>();
}
private ObservableCollection<CANScheduleConfigDto> _listCANScheduleConfigDto = new ObservableCollection<CANScheduleConfigDto>();
/// <summary>
/// CAN 调度表集合。
/// </summary>
public ObservableCollection<CANScheduleConfigDto> ListCANScheduleConfigDto
{
get { return _listCANScheduleConfigDto; }
set { _listCANScheduleConfigDto = value; RaisePropertyChanged(); }
}
private ObservableCollection<CANFdScheduleConfigDto> _listCANFdScheduleConfigDto = new ObservableCollection<CANFdScheduleConfigDto>();
/// <summary>
/// CANFD 调度表集合。
/// </summary>
public ObservableCollection<CANFdScheduleConfigDto> ListCANFdScheduleConfigDto
{
get { return _listCANFdScheduleConfigDto; }
set { _listCANFdScheduleConfigDto = value; RaisePropertyChanged(); }
}
/// <summary>
/// 当前仲裁波特率(对 CAN等同 BaudRate对 CANFDArbBaudRate
/// </summary>
public int CurrentArbBaudRate
{
get
{
return SelectedMode == ZlgCanMode.Can
? (SelectedCANConfigExdDto?.BaudRate ?? 0)
: (SelectedCANFdConfigExdDto?.ArbBaudRate ?? 0);
}
set
{
if (SelectedMode == ZlgCanMode.Can)
{
if (SelectedCANConfigExdDto == null) return;
SelectedCANConfigExdDto.BaudRate = value;
}
else
{
if (SelectedCANFdConfigExdDto == null) return;
SelectedCANFdConfigExdDto.ArbBaudRate = value;
}
RaisePropertyChanged();
RaisePropertyChanged(nameof(CanBaudRate));
RaisePropertyChanged(nameof(CanFdArbBaudRate));
}
}
/// <summary>
/// 当前数据波特率(对 CAN等同 BaudRate对 CANFDDataBaudRate
/// </summary>
public int CurrentDataBaudRate
{
get
{
return SelectedMode == ZlgCanMode.Can
? (SelectedCANConfigExdDto?.BaudRate ?? 0)
: (SelectedCANFdConfigExdDto?.DataBaudRate ?? 0);
}
set
{
if (SelectedMode == ZlgCanMode.Can)
{
if (SelectedCANConfigExdDto == null) return;
SelectedCANConfigExdDto.BaudRate = value;
}
else
{
if (SelectedCANFdConfigExdDto == null) return;
SelectedCANFdConfigExdDto.DataBaudRate = value;
}
RaisePropertyChanged();
RaisePropertyChanged(nameof(CanBaudRate));
RaisePropertyChanged(nameof(CanFdDataBaudRate));
}
}
/// <summary>
/// 当前 ISO 标准使能(仅 CANFD 有意义CAN 固定为 false
/// </summary>
public bool CurrentISOEnable
{
get { return SelectedMode == ZlgCanMode.Can ? false : (SelectedCANFdConfigExdDto?.ISOEnable ?? false); }
set
{
if (SelectedMode == ZlgCanMode.Can)
{
return;
}
if (SelectedCANFdConfigExdDto == null) return;
SelectedCANFdConfigExdDto.ISOEnable = value;
RaisePropertyChanged();
}
}
/// <summary>
/// 当前终端电阻使能(仅 CANFD 有意义CAN 固定为 true驱动侧可忽略
/// </summary>
public bool CurrentResEnable
{
get { return SelectedMode == ZlgCanMode.Can ? true : (SelectedCANFdConfigExdDto?.ResEnable ?? false); }
set
{
if (SelectedMode == ZlgCanMode.Can)
{
return;
}
if (SelectedCANFdConfigExdDto == null) return;
SelectedCANFdConfigExdDto.ResEnable = value;
RaisePropertyChanged();
}
}
/// <summary>
/// 构建并加载命令数据到驱动。
/// </summary>
private void BuildAndLoadCmdDataToDrive()
{
try
{
if (SelectCanLinConfigPro?.CanLinConfigContents == null)
{
ZlgCanDriveService.LoadCmdDataToDrive(new List<CanCmdData>());
return;
}
var writeItems = SelectCanLinConfigPro.CanLinConfigContents
.Where(a => a.RWInfo == RW.Write)
.ToList();
var cmdList = new List<CanCmdData>();
foreach (var item in writeItems)
{
cmdList.Add(new CanCmdData()
{
ConfigName = item.Name,
MsgName = item.MsgFrameName,
SignalName = item.SignalName,
SignalCmdValue = double.TryParse(item.DefautValue, out double result) ? result : 0,
LogicRuleDto = Mapper.Map<LogicRuleDto>(item.LogicRule),
});
}
ZlgCanDriveService.LoadCmdDataToDrive(cmdList);
}
catch (Exception ex)
{
LogService.Warn($"ZLG CAN 构建/下发 CmdData 失败:{ex.Message}");
}
}
/// <summary>
/// 当前 DBC 路径(随模式切换映射到对应 DTO
/// </summary>
public string? CurrentDbcPath
{
get
{
return SelectedMode == ZlgCanMode.Can
? SelectedCANConfigExdDto?.DbcPath
: SelectedCANFdConfigExdDto?.DbcPath;
}
set
{
if (SelectedMode == ZlgCanMode.Can)
{
if (SelectedCANConfigExdDto == null) return;
SelectedCANConfigExdDto.DbcPath = value;
}
else
{
if (SelectedCANFdConfigExdDto == null) return;
SelectedCANFdConfigExdDto.DbcPath = value;
}
RaisePropertyChanged();
}
}
/// <summary>
/// 当前周期(随模式切换映射到对应 DTO
/// </summary>
public int CurrentCycle
{
get
{
return SelectedMode == ZlgCanMode.Can
? (SelectedCANConfigExdDto?.Cycle ?? 0)
: (SelectedCANFdConfigExdDto?.Cycle ?? 0);
}
set
{
if (SelectedMode == ZlgCanMode.Can)
{
if (SelectedCANConfigExdDto == null) return;
SelectedCANConfigExdDto.Cycle = value;
}
else
{
if (SelectedCANFdConfigExdDto == null) return;
SelectedCANFdConfigExdDto.Cycle = value;
}
RaisePropertyChanged();
}
}
/// <summary>
/// 当前调度使能(随模式切换映射到对应 DTO
/// </summary>
public bool CurrentSchEnable
{
get
{
return SelectedMode == ZlgCanMode.Can
? (SelectedCANConfigExdDto?.SchEnable ?? false)
: (SelectedCANFdConfigExdDto?.SchEnable ?? false);
}
set
{
if (SelectedMode == ZlgCanMode.Can)
{
if (SelectedCANConfigExdDto == null) return;
SelectedCANConfigExdDto.SchEnable = value;
}
else
{
if (SelectedCANFdConfigExdDto == null) return;
SelectedCANFdConfigExdDto.SchEnable = value;
}
RaisePropertyChanged();
}
}
/// <summary>
/// CAN 波特率。
/// </summary>
public int CanBaudRate
{
get { return SelectedCANConfigExdDto?.BaudRate ?? 0; }
set
{
if (SelectedCANConfigExdDto == null) return;
SelectedCANConfigExdDto.BaudRate = value;
RaisePropertyChanged();
}
}
/// <summary>
/// CANFD 仲裁波特率。
/// </summary>
public int CanFdArbBaudRate
{
get { return SelectedCANFdConfigExdDto?.ArbBaudRate ?? 0; }
set
{
if (SelectedCANFdConfigExdDto == null) return;
SelectedCANFdConfigExdDto.ArbBaudRate = value;
RaisePropertyChanged();
}
}
/// <summary>
/// CANFD 数据波特率。
/// </summary>
public int CanFdDataBaudRate
{
get { return SelectedCANFdConfigExdDto?.DataBaudRate ?? 0; }
set
{
if (SelectedCANFdConfigExdDto == null) return;
SelectedCANFdConfigExdDto.DataBaudRate = value;
RaisePropertyChanged();
}
}
/// <summary>
/// 匹配选中的配置和 DBC 模型。
/// </summary>
private void MatchSeletedAndCanDbcModel()
{
if (ListCanDbcModel == null || ListCanDbcModel.Count == 0) return;
if (SelectCanLinConfigPro?.CanLinConfigContents == null || SelectCanLinConfigPro.CanLinConfigContents.Count == 0) return;
foreach (var itemCanDbcModel in ListCanDbcModel)
{
var findData = SelectCanLinConfigPro.CanLinConfigContents.FindFirst(a => a.SignalName == itemCanDbcModel.SignalName);
if (findData != null)
{
switch (findData.RWInfo)
{
case RW.Write:
itemCanDbcModel.IsSeletedInfo = 1;
break;
case RW.Read:
itemCanDbcModel.IsSeletedInfo = 2;
break;
default:
itemCanDbcModel.IsSeletedInfo = 0;
break;
}
}
else
{
itemCanDbcModel.IsSeletedInfo = 0;
}
}
}
private DelegateCommand<object>? _canConfigProGridSelectionChangedCmd;
/// <summary>
/// 配置程序选中变化。
/// </summary>
public DelegateCommand<object> CanConfigProGridSelectionChangedCmd
{
get
{
if (_canConfigProGridSelectionChangedCmd == null)
{
_canConfigProGridSelectionChangedCmd = new DelegateCommand<object>(CanConfigProGridSelectionChangedCmdMethod);
}
return _canConfigProGridSelectionChangedCmd;
}
}
private void CanConfigProGridSelectionChangedCmdMethod(object par)
{
if (par == null) return;
if (ZlgCanDriveService.OpenState)
{
// 打开状态下禁止切换配置程序。
return;
}
if (IsCanConfigProActive)
{
// 激活状态下禁止切换配置程序。
return;
}
if (par is SelectionChangedEventArgs) return;
if (par is CanLinConfigPro)
{
SelectCanLinConfigPro = par as CanLinConfigPro;
SyncSelectedConfig();
return;
}
var args = par as SelectionChangedEventArgs;
if (args == null || args.AddedItems == null || args.AddedItems.Count == 0) return;
var selected = args.AddedItems[0] as CanLinConfigPro;
if (selected == null) return;
SelectCanLinConfigPro = selected;
SyncSelectedConfig();
}
private DelegateCommand<object>? _canConfigProGridPreviewMouseLeftButtonDownCmd;
/// <summary>
/// 配置程序切换前拦截(对齐图莫斯 PreviewMouseLeftButtonDown
/// 打开/激活状态下禁止切换,防止状态错乱。
/// </summary>
public DelegateCommand<object> CanConfigProGridPreviewMouseLeftButtonDownCmd
{
get
{
if (_canConfigProGridPreviewMouseLeftButtonDownCmd == null)
{
_canConfigProGridPreviewMouseLeftButtonDownCmd = new DelegateCommand<object>(CanConfigProGridPreviewMouseLeftButtonDownCmdMethod);
}
return _canConfigProGridPreviewMouseLeftButtonDownCmd;
}
}
private void CanConfigProGridPreviewMouseLeftButtonDownCmdMethod(object par)
{
try
{
if (ZlgCanDriveService.OpenState)
{
MessageBox.Show("CAN 已连接,请先关闭后再切换配置程序", "提示", MessageBoxButton.OK, MessageBoxImage.Hand);
if (par is System.Windows.Input.MouseButtonEventArgs e) e.Handled = true;
return;
}
if (IsCanConfigProActive)
{
MessageBox.Show("当前配置程序已激活,请先取消激活后再切换", "提示", MessageBoxButton.OK, MessageBoxImage.Hand);
if (par is System.Windows.Input.MouseButtonEventArgs e) e.Handled = true;
return;
}
}
catch (Exception ex)
{
LogService.Warn($"配置切换拦截异常:{ex.Message}");
}
}
private DelegateCommand? _loadDbcCmd;
/// <summary>
/// 选择 DBC 文件。
/// </summary>
public DelegateCommand LoadDbcCmd
{
get
{
if (_loadDbcCmd == null)
{
_loadDbcCmd = new DelegateCommand(LoadDbcCmdMethod);
}
return _loadDbcCmd;
}
}
private void LoadDbcCmdMethod()
{
try
{
if (SelectCanLinConfigPro == null)
{
MessageBox.Show("选中CAN配置名称后再操作", "提示", MessageBoxButton.OK, MessageBoxImage.Hand);
return;
}
OpenFileDialog openFileDialogInfo = new OpenFileDialog();
openFileDialogInfo.Filter = "(*.dbc;*.dbc)|*.dbc;*.dbc|all|*.*";
openFileDialogInfo.CheckFileExists = true;
openFileDialogInfo.CheckPathExists = true;
var dialogResult = openFileDialogInfo.ShowDialog();
if (dialogResult != true)
{
// 用户取消:保持原值,不清空 CurrentDbcPath
return;
}
var fileName = openFileDialogInfo.FileName;
if (string.IsNullOrWhiteSpace(fileName))
{
return;
}
if (!File.Exists(fileName))
{
MessageBox.Show("文件不存在,请重新选择", "提示", MessageBoxButton.OK, MessageBoxImage.Hand);
return;
}
CurrentDbcPath = fileName;
}
catch (Exception ex)
{
LogService.Error($"选择 DBC 文件失败:{ex}");
MessageBox.Show(ex.Message, "错误", MessageBoxButton.OK, MessageBoxImage.Error);
}
}
private DelegateCommand<object>? _schEnableCmd;
/// <summary>
/// 调度使能写入驱动。
/// </summary>
public DelegateCommand<object> SchEnableCmd
{
get
{
if (_schEnableCmd == null)
{
_schEnableCmd = new DelegateCommand<object>(SchEnableCmdCall);
}
return _schEnableCmd;
}
}
private void SchEnableCmdCall(object par)
{
// 与旧 Toomoss 行为对齐UI 勾选后立即下发到驱动
ZlgCanDriveService.SchEnable = CurrentSchEnable;
}
private DelegateCommand<string>? _canLinConfigProCmd;
/// <summary>
/// 配置程序操作(新建/修改/删除)。
/// </summary>
public DelegateCommand<string> CanLinConfigProCmd
{
get
{
if (_canLinConfigProCmd == null)
{
_canLinConfigProCmd = new DelegateCommand<string>(CanLinConfigProCmdMethod);
}
return _canLinConfigProCmd;
}
}
private void CanLinConfigProCmdMethod(string par)
{
if (string.IsNullOrWhiteSpace(par)) return;
try
{
switch (par)
{
case "Add":
if (IsCanConfigProActive)
{
MessageBox.Show("当前配置已激活,请先取消激活后再新建/修改配置程序", "提示", MessageBoxButton.OK, MessageBoxImage.Hand);
return;
}
if (ZlgCanDriveService.OpenState)
{
MessageBox.Show("请先关闭 CAN 后再新建配置程序", "提示", MessageBoxButton.OK, MessageBoxImage.Hand);
return;
}
DialogService.ShowDialog("DialogCanLinConfigCreateView", new DialogParameters() { { "Name", "" } }, r =>
{
if (r.Result != ButtonResult.OK) return;
try
{
var name = r.Parameters.GetValue<string>("Name")?.Trim();
if (string.IsNullOrWhiteSpace(name))
{
MessageBox.Show("名称不能为空", "提示", MessageBoxButton.OK, MessageBoxImage.Hand);
return;
}
var info = SelectedMode == ZlgCanMode.Can ? CANLIN.CAN : CANLIN.CANFD;
var exists = FreeSql.Select<CanLinConfigPro>()
.Where(a => a.CANLINInfo == info)
.Where(a => a.ConfigName == name)
.Any();
if (exists)
{
MessageBox.Show("名称已存在,请更换名称", "提示", MessageBoxButton.OK, MessageBoxImage.Hand);
return;
}
long newProId = 0;
FreeSql.Transaction(() =>
{
if (SelectedMode == ZlgCanMode.Can)
{
var exdList = FreeSql.Insert<CANConfigExd>(new CANConfigExd()
{
BaudRate = 500000,
DbcPath = string.Empty,
Cycle = 100,
SchEnable = false,
}).ExecuteInserted();
var exd = exdList?.FirstOrDefault();
if (exd == null)
{
throw new InvalidOperationException("创建 CAN 扩展配置失败");
}
var proList = FreeSql.Insert<CanLinConfigPro>(new CanLinConfigPro()
{
ConfigName = name,
CANLINInfo = CANLIN.CAN,
CANConfigExdId = exd.Id,
}).ExecuteInserted();
var pro = proList?.FirstOrDefault();
if (pro == null)
{
throw new InvalidOperationException("创建 CAN 配置程序失败");
}
newProId = pro.Id;
}
else
{
var exdList = FreeSql.Insert<CANFdConfigExd>(new CANFdConfigExd()
{
ArbBaudRate = 500000,
DataBaudRate = 2000000,
ISOEnable = true,
ResEnable = false,
DbcPath = string.Empty,
Cycle = 100,
SchEnable = false,
}).ExecuteInserted();
var exd = exdList?.FirstOrDefault();
if (exd == null)
{
throw new InvalidOperationException("创建 CANFD 扩展配置失败");
}
var proList = FreeSql.Insert<CanLinConfigPro>(new CanLinConfigPro()
{
ConfigName = name,
CANLINInfo = CANLIN.CANFD,
CANFdConfigExdId = exd.Id,
}).ExecuteInserted();
var pro = proList?.FirstOrDefault();
if (pro == null)
{
throw new InvalidOperationException("创建 CANFD 配置程序失败");
}
newProId = pro.Id;
}
});
InitLoadCanConfigPro();
SelectCanLinConfigPro = _canLinConfigPros.Find(a => a.Id == newProId);
SyncSelectedConfig();
MatchSeletedAndCanDbcModel();
}
catch (Exception ex)
{
LogService.Error($"ZLG 新建配置程序失败:{ex}");
MessageBox.Show(ex.Message, "错误", MessageBoxButton.OK, MessageBoxImage.Error);
}
});
break;
case "Edit":
if (SelectCanLinConfigPro == null)
{
MessageBox.Show("选中后再操作", "提示", MessageBoxButton.OK, MessageBoxImage.Hand);
return;
}
if (IsCanConfigProActive)
{
MessageBox.Show("当前配置已激活,请先取消激活后再修改配置程序", "提示", MessageBoxButton.OK, MessageBoxImage.Hand);
return;
}
if (ZlgCanDriveService.OpenState)
{
MessageBox.Show("请先关闭 CAN 后再修改配置程序", "提示", MessageBoxButton.OK, MessageBoxImage.Hand);
return;
}
DialogService.ShowDialog("DialogCanLinConfigCreateView", new DialogParameters() { { "Name", SelectCanLinConfigPro.ConfigName } }, r =>
{
if (r.Result != ButtonResult.OK) return;
try
{
var name = r.Parameters.GetValue<string>("Name")?.Trim();
if (string.IsNullOrWhiteSpace(name))
{
MessageBox.Show("名称不能为空", "提示", MessageBoxButton.OK, MessageBoxImage.Hand);
return;
}
var info = SelectedMode == ZlgCanMode.Can ? CANLIN.CAN : CANLIN.CANFD;
var exists = FreeSql.Select<CanLinConfigPro>()
.Where(a => a.CANLINInfo == info)
.Where(a => a.ConfigName == name)
.Where(a => a.Id != SelectCanLinConfigPro.Id)
.Any();
if (exists)
{
MessageBox.Show("名称已存在,请更换名称", "提示", MessageBoxButton.OK, MessageBoxImage.Hand);
return;
}
FreeSql.Update<CanLinConfigPro>()
.Set(a => a.ConfigName, name)
.Where(a => a.Id == SelectCanLinConfigPro.Id)
.ExecuteAffrows();
ReloadCurrentConfigPro();
}
catch (Exception ex)
{
LogService.Error($"ZLG 修改配置程序失败:{ex}");
MessageBox.Show(ex.Message, "错误", MessageBoxButton.OK, MessageBoxImage.Error);
}
});
break;
case "Delete":
if (SelectCanLinConfigPro == null)
{
MessageBox.Show("选中后再操作", "提示", MessageBoxButton.OK, MessageBoxImage.Hand);
return;
}
if (IsCanConfigProActive)
{
MessageBox.Show("当前配置已激活,请先取消激活后再删除配置程序", "提示", MessageBoxButton.OK, MessageBoxImage.Hand);
return;
}
if (ZlgCanDriveService.OpenState)
{
MessageBox.Show("请先关闭 CAN 后再删除配置程序", "提示", MessageBoxButton.OK, MessageBoxImage.Hand);
return;
}
if (MessageBox.Show($"确定删除配置程序:{SelectCanLinConfigPro.ConfigName}", "确认", MessageBoxButton.OKCancel, MessageBoxImage.Warning) != MessageBoxResult.OK)
{
return;
}
// 删除主表与内容
var repo = FreeSql.GetRepository<CanLinConfigPro>();
repo.DbContextOptions.EnableCascadeSave = true;
var delList = repo.Select
.Include(a => a.CANConfigExd)
.Include(a => a.CANFdConfigExd)
.IncludeMany(a => a.CanLinConfigContents)
.IncludeMany(a => a.CanScheduleConfigs)
.IncludeMany(a => a.CanFdScheduleConfigs)
.Where(a => a.Id == SelectCanLinConfigPro.Id)
.ToList();
repo.Delete(delList);
foreach (var item in delList)
{
// 允许配置在 CAN/CANFD 间切换保存后同时具备两套扩展表,此处统一清理避免残留孤儿记录。
if (item.CANConfigExdId > 0)
{
FreeSql.Delete<CANConfigExd>(item.CANConfigExdId).ExecuteAffrows();
}
if (item.CANFdConfigExdId > 0)
{
FreeSql.Delete<CANFdConfigExd>(item.CANFdConfigExdId).ExecuteAffrows();
}
}
SelectCanLinConfigPro = null;
SelectedCANConfigExdDto = null;
SelectedCANFdConfigExdDto = null;
InitLoadCanConfigPro();
ListCanDbcModel = new ObservableCollection<CanDbcModel>();
break;
case "Active":
// 激活到取消的状态的判断
if (IsCanConfigProActive)
{
IsCanConfigProActive = false;
IsCANConfigDatagridActive = true;
// 停止调度/发送,避免“取消激活但仍在发送”
ZlgCanDriveService.StopSchedule();
ZlgCanDriveService.IsCycleSend = false;
ZlgCanDriveService.LoadCmdDataToDrive(new List<CanCmdData>());
OpTip = "已取消激活";
return;
}
if (!ZlgCanDriveService.OpenState)
{
MessageBox.Show("请确保 CAN 已连接后再激活", "提示", MessageBoxButton.OK, MessageBoxImage.Hand);
return;
}
if (SelectCanLinConfigPro == null)
{
MessageBox.Show("选中后再操作", "提示", MessageBoxButton.OK, MessageBoxImage.Hand);
return;
}
if (string.IsNullOrWhiteSpace(CurrentDbcPath))
{
MessageBox.Show("请先选择并解析 DBC 文件后再激活", "提示", MessageBoxButton.OK, MessageBoxImage.Hand);
return;
}
// 激活前强制按“当前配置的 DBC 路径”重新解析,避免 DbcParserState 来自其它配置导致错配。
try
{
ListCanDbcModel = ZlgCanDriveService.StartDbc(CurrentDbcPath);
MatchSeletedAndCanDbcModel();
}
catch (Exception ex)
{
LogService.Error($"ZLG 激活前解析 DBC 失败:{ex}");
MessageBox.Show(ex.Message, "错误", MessageBoxButton.OK, MessageBoxImage.Error);
return;
}
IsCanConfigProActive = true;
IsCANConfigDatagridActive = false;
// 当前使用的配置程序
ZlgCanDriveService.InitCanConfig(SelectCanLinConfigPro);
// 下发指令集合与调度表
BuildAndLoadCmdDataToDrive();
if (SelectedMode == ZlgCanMode.Can)
{
ZlgCanDriveService.SetScheduleConfigs(ListCANScheduleConfigDto?.ToList() ?? new List<CANScheduleConfigDto>());
}
else
{
ZlgCanDriveService.SetScheduleConfigs(ListCANFdScheduleConfigDto?.ToList() ?? new List<CANFdScheduleConfigDto>());
}
OpTip = "已激活当前配置";
break;
}
}
catch (Exception ex)
{
LogService.Error($"ZLG 配置程序操作失败:{par}{ex}");
MessageBox.Show(ex.Message, "错误", MessageBoxButton.OK, MessageBoxImage.Error);
}
}
private DelegateCommand? _scheduleConfigCmd;
/// <summary>
/// 调度表配置(弹窗)。
/// </summary>
public DelegateCommand ScheduleConfigCmd
{
get
{
if (_scheduleConfigCmd == null)
{
_scheduleConfigCmd = new DelegateCommand(ScheduleConfigCmdMethod);
}
return _scheduleConfigCmd;
}
}
private void ScheduleConfigCmdMethod()
{
try
{
if (SelectCanLinConfigPro == null)
{
MessageBox.Show("选中CAN配置名称后再操作", "提示", MessageBoxButton.OK, MessageBoxImage.Hand);
return;
}
var msgList = ZlgCanDriveService.CmdData.GroupBy(a => a.MsgName).Select(a => a.Key).Where(a => !string.IsNullOrWhiteSpace(a)).ToList();
if (msgList == null || msgList.Count == 0)
{
MessageBox.Show("未发现写入指令数据CmdData 为空),无法配置调度表", "提示", MessageBoxButton.OK, MessageBoxImage.Hand);
return;
}
if (SelectedMode == ZlgCanMode.Can)
{
DialogService.ShowDialog("DialogCANSchConfigView", new DialogParameters()
{
{ "ListMsg", msgList },
{ "ListCANScheduleConfigDto", ListCANScheduleConfigDto },
{ "SelectCanLinConfigProId", SelectCanLinConfigPro.Id },
}, r =>
{
if (r.Result != ButtonResult.OK) return;
ListCANScheduleConfigDto = r.Parameters.GetValue<ObservableCollection<CANScheduleConfigDto>>("ReturnValue") ?? new ObservableCollection<CANScheduleConfigDto>();
SelectCanLinConfigPro.CanScheduleConfigs = Mapper.Map<List<CANScheduleConfig>>(ListCANScheduleConfigDto.ToList());
ReloadCurrentConfigPro();
});
}
else
{
DialogService.ShowDialog("DialogCANFdSchConfigView", new DialogParameters()
{
{ "ListMsg", msgList },
{ "ListCANFdScheduleConfigDto", ListCANFdScheduleConfigDto },
{ "SelectCanLinConfigProId", SelectCanLinConfigPro.Id },
}, r =>
{
if (r.Result != ButtonResult.OK) return;
ListCANFdScheduleConfigDto = r.Parameters.GetValue<ObservableCollection<CANFdScheduleConfigDto>>("ReturnValue") ?? new ObservableCollection<CANFdScheduleConfigDto>();
SelectCanLinConfigPro.CanFdScheduleConfigs = Mapper.Map<List<CANFdScheduleConfig>>(ListCANFdScheduleConfigDto.ToList());
ReloadCurrentConfigPro();
});
}
}
catch (Exception ex)
{
LogService.Error($"调度表配置失败:{ex}");
MessageBox.Show(ex.Message, "错误", MessageBoxButton.OK, MessageBoxImage.Error);
}
}
private DelegateCommand<string>? _writeReadConfigCmd;
/// <summary>
/// 写入/读取/删除 信号配置项。
/// </summary>
public DelegateCommand<string> WriteReadConfigCmd
{
get
{
if (_writeReadConfigCmd == null)
{
_writeReadConfigCmd = new DelegateCommand<string>(WriteReadConfigCmdMethod);
}
return _writeReadConfigCmd;
}
}
private void WriteReadConfigCmdMethod(string par)
{
if (string.IsNullOrWhiteSpace(par)) return;
if (SelectCanLinConfigPro == null)
{
MessageBox.Show("选中CAN配置名称后再操作", "提示", MessageBoxButton.OK, MessageBoxImage.Hand);
return;
}
if (string.Equals(par, "OpenDialog", StringComparison.OrdinalIgnoreCase))
{
if (!ZlgCanDriveService.OpenState)
{
MessageBox.Show("当前未连接 CAN/CANFD无法打开【读写设置】。请先连接设备后再操作。", "提示", MessageBoxButton.OK, MessageBoxImage.Hand);
return;
}
if (ListCanDbcModel == null || ListCanDbcModel.Count == 0)
{
MessageBox.Show("当前信号集合为空,无法打开【读写设置】。请先解析 DBC 并确保信号列表已加载后再操作。", "提示", MessageBoxButton.OK, MessageBoxImage.Hand);
return;
}
OpenRwDialog();
return;
}
if (IsCanConfigProActive)
{
MessageBox.Show("当前配置已激活,请先取消激活后再修改写入/读取配置", "提示", MessageBoxButton.OK, MessageBoxImage.Hand);
return;
}
if (SelectedCanDbcModel == null)
{
MessageBox.Show("请在右侧信号表中选中一个信号后再操作", "提示", MessageBoxButton.OK, MessageBoxImage.Hand);
return;
}
if (string.IsNullOrWhiteSpace(SelectedCanDbcModel.SignalName) || string.IsNullOrWhiteSpace(SelectedCanDbcModel.MsgName))
{
MessageBox.Show("选中的信号数据不完整SignalName/MsgName 为空)", "提示", MessageBoxButton.OK, MessageBoxImage.Hand);
return;
}
try
{
if (par == "Delete")
{
FreeSql.Delete<CanLinRWConfig>()
.Where(a => a.CanLinConfigProId == SelectCanLinConfigPro.Id)
.Where(a => a.SignalName == SelectedCanDbcModel.SignalName)
.ExecuteAffrows();
ReloadCurrentConfigPro();
OpTip = "已删除配置项";
return;
}
var rw = par == "Write" ? RW.Write : RW.Read;
// 防重复:同一个 SignalName + RWInfo 只允许一条
var exists = FreeSql.Select<CanLinRWConfig>()
.Where(a => a.CanLinConfigProId == SelectCanLinConfigPro.Id)
.Where(a => a.SignalName == SelectedCanDbcModel.SignalName)
.Where(a => a.RWInfo == rw)
.Any();
if (exists)
{
OpTip = "配置已存在";
return;
}
FreeSql.Insert<CanLinRWConfig>(new CanLinRWConfig()
{
Name = SelectedCanDbcModel.SignalName,
SignalName = SelectedCanDbcModel.SignalName,
MsgFrameName = SelectedCanDbcModel.MsgName,
CanLinConfigProId = SelectCanLinConfigPro.Id,
DefautValue = "0",
RWInfo = rw,
LogicRuleId = 0,
}).ExecuteInserted();
ReloadCurrentConfigPro();
OpTip = rw == RW.Write ? "已加入写入配置" : "已加入读取配置";
}
catch (Exception ex)
{
LogService.Error($"ZLG 写入/读取配置操作失败:{par}{ex}");
MessageBox.Show(ex.Message, "错误", MessageBoxButton.OK, MessageBoxImage.Error);
}
}
private void ReloadCurrentConfigPro()
{
var id = SelectCanLinConfigPro?.Id;
InitLoadCanConfigPro();
if (id != null)
{
SelectCanLinConfigPro = _canLinConfigPros.Find(a => a.Id == id.Value);
SyncSelectedConfig();
}
MatchSeletedAndCanDbcModel();
}
private DelegateCommand<string>? _canOpCmd;
/// <summary>
/// CAN 操作命令。
/// </summary>
public DelegateCommand<string> CanOpCmd
{
get
{
if (_canOpCmd == null)
{
_canOpCmd = new DelegateCommand<string>(CanOpCmdMethod);
}
return _canOpCmd;
}
}
private void CanOpCmdMethod(string par)
{
if (string.IsNullOrWhiteSpace(par))
{
return;
}
try
{
switch (par)
{
case "Open":
if (ComActionService.IsCanToDoWork() == false)
{
MessageBox.Show("请关闭LIN连接后才能开启CAN同一个时刻只能有一个通信驱动压缩机", "提示", MessageBoxButton.OK, MessageBoxImage.Hand);
return;
}
if (ZlgLinDriveService.OpenState)
{
MessageBox.Show("请先关闭 ZLG LIN 连接后再开启 ZLG CAN", "提示", MessageBoxButton.OK, MessageBoxImage.Hand);
return;
}
if (SelectCanLinConfigPro == null)
{
MessageBox.Show("选中CAN配置名称后再操作", "提示", MessageBoxButton.OK, MessageBoxImage.Hand);
return;
}
if (SelectedMode == ZlgCanMode.Can)
{
if (SelectedCANConfigExdDto == null)
{
MessageBox.Show("CAN配置为空", "提示", MessageBoxButton.OK, MessageBoxImage.Hand);
return;
}
// ZLG 底层实际为 CANFD 通道CAN 经典帧使用 arbitration 波特率data 亦沿用,保持一致即可)
ZlgCanDriveService.UpdateConfig(0, (uint)SelectedCANConfigExdDto.BaudRate, (uint)SelectedCANConfigExdDto.BaudRate, resEnable: true);
}
else
{
if (SelectedCANFdConfigExdDto == null)
{
MessageBox.Show("CANFD配置为空", "提示", MessageBoxButton.OK, MessageBoxImage.Hand);
return;
}
ZlgCanDriveService.UpdateConfig(0, (uint)SelectedCANFdConfigExdDto.ArbBaudRate, (uint)SelectedCANFdConfigExdDto.DataBaudRate, SelectedCANFdConfigExdDto.ResEnable);
}
ZlgCanDriveService.StartCanDrive();
if (ZlgCanDriveService.OpenState)
{
LastError = null;
OpTip = "CAN 已连接";
ConfigService.CanLinRunStateModel.CurSysSelectedCanLin = SelectedMode == ZlgCanMode.Can ? CanLinEnum.Can : CanLinEnum.CANFD;
}
else
{
OpTip = "CAN 连接失败";
MessageBox.Show("CAN 连接失败OpenState=false请检查设备/驱动/参数。", "提示", MessageBoxButton.OK, MessageBoxImage.Hand);
return;
}
// 自动解析 DBC
if (!string.IsNullOrWhiteSpace(CurrentDbcPath))
{
ListCanDbcModel = ZlgCanDriveService.StartDbc(CurrentDbcPath);
MatchSeletedAndCanDbcModel();
}
// 将当前配置的 CmdData 下发到驱动(用于事件驱动增量发送)
BuildAndLoadCmdDataToDrive();
break;
case "Close":
ZlgCanDriveService.CloseDevice();
ConfigService.CanLinRunStateModel.CurSysSelectedCanLin = CanLinEnum.No;
LastError = null;
OpTip = "CAN 已关闭";
// 关闭设备时自动退出激活,恢复可切换状态
IsCanConfigProActive = false;
IsCANConfigDatagridActive = true;
break;
case "Parse":
if (!ZlgCanDriveService.OpenState)
{
MessageBox.Show("请先打开CAN后再解析", "提示", MessageBoxButton.OK, MessageBoxImage.Hand);
return;
}
if (string.IsNullOrWhiteSpace(CurrentDbcPath))
{
MessageBox.Show("请选择DBC文件后再操作", "提示", MessageBoxButton.OKCancel, MessageBoxImage.Hand);
return;
}
ListCanDbcModel = ZlgCanDriveService.StartDbc(CurrentDbcPath);
MatchSeletedAndCanDbcModel();
LastError = null;
OpTip = "DBC 已解析";
break;
case "CycleSend":
if (!ZlgCanDriveService.OpenState)
{
MessageBox.Show("请先打开 CAN 后再进行循环发送", "提示", MessageBoxButton.OK, MessageBoxImage.Hand);
return;
}
if (!ZlgCanDriveService.DbcParserState)
{
MessageBox.Show("请先解析 DBC 后再进行循环发送", "提示", MessageBoxButton.OK, MessageBoxImage.Hand);
return;
}
// 与图莫斯一致:第一次点击开启,第二次点击关闭
if (!ZlgCanDriveService.IsCycleSend)
{
// 开启前:确保最新 CmdData 已下发
BuildAndLoadCmdDataToDrive();
// 同步 SchEnable防止 UI 勾选但未触发 Command 导致服务端状态不一致)
ZlgCanDriveService.SchEnable = CurrentSchEnable;
if (ZlgCanDriveService.SchEnable)
{
// 使用调度表:校验每个 MsgName 都配置了周期
var groupMsg = ZlgCanDriveService.CmdData
.Where(a => !string.IsNullOrWhiteSpace(a.MsgName))
.GroupBy(a => a.MsgName)
.Select(g => g.Key)
.ToList();
if (groupMsg.Count == 0)
{
MessageBox.Show("未发现可发送的消息帧CmdData.MsgName 为空)", "提示", MessageBoxButton.OK, MessageBoxImage.Hand);
return;
}
if (SelectedMode == ZlgCanMode.Can)
{
foreach (var msg in groupMsg)
{
if (!ListCANScheduleConfigDto.Any(a => string.Equals(a.MsgName, msg, StringComparison.Ordinal)))
{
MessageBox.Show($"你使能了调度表,但是调度表中没有设置【{msg}】信息,请设置后再操作", "提示", MessageBoxButton.OK, MessageBoxImage.Hand);
return;
}
}
if (ListCANScheduleConfigDto == null || ListCANScheduleConfigDto.Count == 0)
{
MessageBox.Show("调度表配置为空数据,请检查!将无法发送数据", "提示", MessageBoxButton.OK, MessageBoxImage.Hand);
return;
}
ZlgCanDriveService.SetScheduleConfigs(ListCANScheduleConfigDto.ToList());
}
else
{
foreach (var msg in groupMsg)
{
if (!ListCANFdScheduleConfigDto.Any(a => string.Equals(a.MsgName, msg, StringComparison.Ordinal)))
{
MessageBox.Show($"你使能了调度表,但是调度表中没有设置【{msg}】信息,请设置后再操作", "提示", MessageBoxButton.OK, MessageBoxImage.Hand);
return;
}
}
if (ListCANFdScheduleConfigDto == null || ListCANFdScheduleConfigDto.Count == 0)
{
MessageBox.Show("调度表配置为空数据,请检查!将无法发送数据", "提示", MessageBoxButton.OK, MessageBoxImage.Hand);
return;
}
ZlgCanDriveService.SetScheduleConfigs(ListCANFdScheduleConfigDto.ToList());
}
ZlgCanDriveService.StartSchedule();
}
else
{
// 不使用调度表:按当前配置周期做精确循环发送
var cycle = Math.Max(1, CurrentCycle);
ZlgCanDriveService.StartPrecisionCycleSend(cycle);
}
OpTip = "循环发送:已开启";
}
else
{
ZlgCanDriveService.IsCycleSend = false;
ZlgCanDriveService.StopSchedule();
OpTip = "循环发送:已关闭";
}
break;
case "CycleRecive":
ZlgCanDriveService.SetReceiveEnabled(!ZlgCanDriveService.IsCycleRevice);
OpTip = ZlgCanDriveService.IsCycleRevice ? "循环接收:已开启" : "循环接收:已关闭";
break;
case "Save":
if (SelectCanLinConfigPro == null)
{
MessageBox.Show("选中CAN配置名称后再操作", "提示", MessageBoxButton.OK, MessageBoxImage.Hand);
return;
}
// 允许在 UI 上修改当前配置的模式CAN/CANFD保存时同步更新 CanLinConfigPro.CANLINInfo。
FreeSql.Transaction(() =>
{
if (SelectedMode == ZlgCanMode.Can)
{
if (SelectedCANConfigExdDto == null || SelectedCANConfigExdDto.Id <= 0)
{
// 若原配置为 CANFD切换到 CAN 时可能尚未存在 CAN 扩展配置,这里按默认值创建。
var inserted = FreeSql.Insert<CANConfigExd>(new CANConfigExd()
{
BaudRate = 500000,
DbcPath = string.Empty,
Cycle = 100,
SchEnable = false,
}).ExecuteInserted();
var exd = inserted?.FirstOrDefault();
if (exd == null) throw new InvalidOperationException("创建 CAN 扩展配置失败");
SelectedCANConfigExdDto = Mapper.Map<CANConfigExdDto>(exd);
}
FreeSql.Update<CANConfigExd>()
.Set(a => a.DbcPath, SelectedCANConfigExdDto.DbcPath)
.Set(a => a.Cycle, SelectedCANConfigExdDto.Cycle)
.Set(a => a.BaudRate, SelectedCANConfigExdDto.BaudRate)
.Set(a => a.SchEnable, SelectedCANConfigExdDto.SchEnable)
.Where(a => a.Id == SelectedCANConfigExdDto.Id)
.ExecuteUpdated();
FreeSql.Update<CanLinConfigPro>()
.Set(a => a.CANLINInfo, CANLIN.CAN)
.Set(a => a.CANConfigExdId, SelectedCANConfigExdDto.Id)
.Where(a => a.Id == SelectCanLinConfigPro.Id)
.ExecuteAffrows();
}
else
{
if (SelectedCANFdConfigExdDto == null || SelectedCANFdConfigExdDto.Id <= 0)
{
// 若原配置为 CAN切换到 CANFD 时可能尚未存在 CANFD 扩展配置,这里按默认值创建。
var inserted = FreeSql.Insert<CANFdConfigExd>(new CANFdConfigExd()
{
ArbBaudRate = 500000,
DataBaudRate = 2000000,
ISOEnable = true,
ResEnable = false,
DbcPath = string.Empty,
Cycle = 100,
SchEnable = false,
}).ExecuteInserted();
var exd = inserted?.FirstOrDefault();
if (exd == null) throw new InvalidOperationException("创建 CANFD 扩展配置失败");
SelectedCANFdConfigExdDto = Mapper.Map<CANFdConfigExdDto>(exd);
}
FreeSql.Update<CANFdConfigExd>()
.Set(a => a.DbcPath, SelectedCANFdConfigExdDto.DbcPath)
.Set(a => a.Cycle, SelectedCANFdConfigExdDto.Cycle)
.Set(a => a.DataBaudRate, SelectedCANFdConfigExdDto.DataBaudRate)
.Set(a => a.ArbBaudRate, SelectedCANFdConfigExdDto.ArbBaudRate)
.Set(a => a.ISOEnable, SelectedCANFdConfigExdDto.ISOEnable)
.Set(a => a.ResEnable, SelectedCANFdConfigExdDto.ResEnable)
.Set(a => a.SchEnable, SelectedCANFdConfigExdDto.SchEnable)
.Where(a => a.Id == SelectedCANFdConfigExdDto.Id)
.ExecuteUpdated();
FreeSql.Update<CanLinConfigPro>()
.Set(a => a.CANLINInfo, CANLIN.CANFD)
.Set(a => a.CANFdConfigExdId, SelectedCANFdConfigExdDto.Id)
.Where(a => a.Id == SelectCanLinConfigPro.Id)
.ExecuteAffrows();
}
});
ReloadCurrentConfigPro();
LastError = null;
OpTip = "配置已保存";
break;
}
}
catch (Exception ex)
{
LastError = ex.Message;
OpTip = "操作失败";
LogService.Error($"ZLG CAN 操作失败:{par}{ex}");
MessageBox.Show(ex.Message, "错误", MessageBoxButton.OK, MessageBoxImage.Error);
}
}
}
}