周立功的CAN /FD实现

This commit is contained in:
2026-02-06 12:34:34 +08:00
parent 2e8ad1cffa
commit 74338fdb3a
13 changed files with 4260 additions and 310 deletions

View File

@@ -0,0 +1,753 @@
using CapMachine.Core;
using CapMachine.Model.CANLIN;
using CapMachine.Wpf.Dtos;
using CapMachine.Wpf.Services;
using FreeSql;
using Prism.Commands;
using Prism.Services.Dialogs;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Windows;
using System.Windows.Data;
namespace CapMachine.Wpf.ViewModels
{
/// <summary>
/// ZLG CAN/LIN 读写配置三栏管理弹窗 ViewModel。
/// 左侧:写入/读取配置;右侧:信号全集候选池;统一保存落库。
/// </summary>
public class DialogZlgCanLinRwConfigViewModel : DialogViewModel
{
private readonly IFreeSql _freeSql;
private readonly ILogService _logService;
private readonly LogicRuleService _logicRuleService;
private long _canLinConfigProId;
/// <summary>
/// 构造函数。
/// </summary>
/// <param name="freeSql">FreeSql。</param>
/// <param name="logService">日志。</param>
/// <param name="logicRuleService">逻辑规则服务。</param>
public DialogZlgCanLinRwConfigViewModel(IFreeSql freeSql, ILogService logService, LogicRuleService logicRuleService)
{
_freeSql = freeSql;
_logService = logService;
_logicRuleService = logicRuleService;
Title = "读写设置";
WriteConfigs = new ObservableCollection<CanLinRWConfigDto>();
ReadConfigs = new ObservableCollection<CanLinRWConfigDto>();
SignalCandidates = new ObservableCollection<SignalCandidate>();
SignalTree = new ObservableCollection<SignalFrameNode>();
SignalCandidatesView = CollectionViewSource.GetDefaultView(SignalCandidates);
SignalCandidatesView.Filter = FilterSignalCandidate;
WriteNameCbxItems = new ObservableCollection<CbxItems>()
{
new CbxItems(){ Key="转速",Text="转速"},
new CbxItems(){ Key="功率限制",Text="功率限制"},
new CbxItems(){ Key="使能",Text="使能"},
new CbxItems(){ Key="Anti_Sleep",Text="Anti_Sleep"},
new CbxItems(){ Key="PTC使能",Text="PTC使能"},
new CbxItems(){ Key="PTC功率",Text="PTC功率"},
new CbxItems(){ Key="PTC水流量",Text="PTC水流量"},
new CbxItems(){ Key="PTC水温",Text="PTC水温"},
};
ReadNameCbxItems = new ObservableCollection<CbxItems>()
{
new CbxItems(){ Key="通讯Cmp转速",Text="通讯Cmp转速"},
new CbxItems(){ Key="通讯Cmp母线电压",Text="通讯Cmp母线电压"},
new CbxItems(){ Key="通讯Cmp母线电流",Text="通讯Cmp母线电流"},
new CbxItems(){ Key="通讯Cmp逆变器温度",Text="通讯Cmp逆变器温度"},
new CbxItems(){ Key="通讯Cmp相电流",Text="通讯Cmp相电流"},
new CbxItems(){ Key="通讯Cmp功率",Text="通讯Cmp功率"},
new CbxItems(){ Key="通讯Cmp芯片温度",Text="通讯Cmp芯片温度"},
new CbxItems(){ Key="通讯PTC入水温度",Text="通讯PTC入水温度"},
new CbxItems(){ Key="通讯PTC出水温度",Text="通讯PTC出水温度"},
new CbxItems(){ Key="通讯PTC峰值电流",Text="通讯PTC峰值电流"},
new CbxItems(){ Key="通讯PTC母线电流",Text="通讯PTC母线电流"},
new CbxItems(){ Key="通讯PTC膜温",Text="通讯PTC膜温"},
new CbxItems(){ Key="通讯PTC模块温度",Text="通讯PTC模块温度"},
};
IsEditable = true;
}
/// <summary>
/// 是否允许编辑(由调用方根据 Active/打开状态决定)。
/// </summary>
public bool IsEditable { get; private set; }
/// <summary>
/// 逻辑规则集合(下拉框 ItemsSource
/// </summary>
public IReadOnlyList<LogicRuleDto> LogicRuleDtos => _logicRuleService.LogicRuleDtos;
/// <summary>
/// 写入配置“名称”下拉框集合(参考 CANConfigViewModel
/// </summary>
public ObservableCollection<CbxItems> WriteNameCbxItems { get; private set; }
/// <summary>
/// 读取配置“名称”下拉框集合(参考 CANConfigViewModel
/// </summary>
public ObservableCollection<CbxItems> ReadNameCbxItems { get; private set; }
/// <summary>
/// 写入配置集合。
/// </summary>
public ObservableCollection<CanLinRWConfigDto> WriteConfigs { get; private set; }
/// <summary>
/// 读取配置集合。
/// </summary>
public ObservableCollection<CanLinRWConfigDto> ReadConfigs { get; private set; }
/// <summary>
/// 信号候选集合(右侧池)。
/// </summary>
public ObservableCollection<SignalCandidate> SignalCandidates { get; private set; }
/// <summary>
/// 信号树(按帧分组)。
/// </summary>
public ObservableCollection<SignalFrameNode> SignalTree { get; private set; }
/// <summary>
/// 候选信号视图(含过滤)。
/// </summary>
public ICollectionView SignalCandidatesView { get; private set; }
private string? _signalFilterText;
/// <summary>
/// 信号过滤文本(按 MsgName/SignalName/Name/Desc 匹配)。
/// </summary>
public string? SignalFilterText
{
get { return _signalFilterText; }
set
{
_signalFilterText = value;
RaisePropertyChanged();
SignalCandidatesView.Refresh();
RebuildSignalTree();
}
}
/// <summary>
/// 当前选中的候选信号。
/// </summary>
public SignalCandidate? SelectedSignalCandidate { get; set; }
/// <summary>
/// 当前选中的写入配置行。
/// </summary>
public CanLinRWConfigDto? SelectedWriteConfig { get; set; }
/// <summary>
/// 当前选中的读取配置行。
/// </summary>
public CanLinRWConfigDto? SelectedReadConfig { get; set; }
private DelegateCommand<object>? _signalTreeSelectionChangedCmd;
/// <summary>
/// 右侧信号树选中变化(仅当选中叶子节点时回写 SelectedSignalCandidate
/// </summary>
public DelegateCommand<object> SignalTreeSelectionChangedCmd =>
_signalTreeSelectionChangedCmd ??= new DelegateCommand<object>(SignalTreeSelectionChangedCmdMethod);
private void SignalTreeSelectionChangedCmdMethod(object par)
{
if (par is SignalCandidate leaf)
{
SelectedSignalCandidate = leaf;
RaisePropertyChanged(nameof(SelectedSignalCandidate));
return;
}
if (par is SignalFrameNode)
{
// 选中父节点时不变更 SelectedSignalCandidate
return;
}
}
private DelegateCommand? _addToWriteCmd;
/// <summary>
/// 将右侧选中信号添加到写入配置。
/// </summary>
public DelegateCommand AddToWriteCmd => _addToWriteCmd ??= new DelegateCommand(AddToWriteCmdMethod);
private void AddToWriteCmdMethod()
{
if (!IsEditable)
{
MessageBox.Show("当前状态禁止修改", "提示", MessageBoxButton.OK, MessageBoxImage.Hand);
return;
}
if (SelectedSignalCandidate == null)
{
MessageBox.Show("请先在右侧信号集合中选中一条", "提示", MessageBoxButton.OK, MessageBoxImage.Hand);
return;
}
if (string.IsNullOrWhiteSpace(SelectedSignalCandidate.SignalName) || string.IsNullOrWhiteSpace(SelectedSignalCandidate.MsgName))
{
MessageBox.Show("选中的信号数据不完整MsgName/SignalName 为空)", "提示", MessageBoxButton.OK, MessageBoxImage.Hand);
return;
}
if (WriteConfigs.Any(a => string.Equals(a.SignalName, SelectedSignalCandidate.SignalName, StringComparison.Ordinal) && a.RWInfo == RW.Write))
{
MessageBox.Show("该信号已在写入配置中,无需重复添加", "提示", MessageBoxButton.OK, MessageBoxImage.Hand);
return;
}
if (ReadConfigs.Any(a => string.Equals(a.SignalName, SelectedSignalCandidate.SignalName, StringComparison.Ordinal) && a.RWInfo == RW.Read))
{
MessageBox.Show("该信号已在读取配置中,同一个信号不允许同时配置为写入与读取", "提示", MessageBoxButton.OK, MessageBoxImage.Hand);
return;
}
WriteConfigs.Add(new CanLinRWConfigDto
{
Id = 0,
RWInfo = RW.Write,
Name = string.IsNullOrWhiteSpace(SelectedSignalCandidate.Name) ? SelectedSignalCandidate.SignalName : SelectedSignalCandidate.Name,
MsgFrameName = SelectedSignalCandidate.MsgName,
SignalName = SelectedSignalCandidate.SignalName,
DefautValue = "0",
LogicRuleId = 0,
});
RebuildSignalTree();
}
private DelegateCommand? _addToReadCmd;
/// <summary>
/// 将右侧选中信号添加到读取配置。
/// </summary>
public DelegateCommand AddToReadCmd => _addToReadCmd ??= new DelegateCommand(AddToReadCmdMethod);
private void AddToReadCmdMethod()
{
if (!IsEditable)
{
MessageBox.Show("当前状态禁止修改", "提示", MessageBoxButton.OK, MessageBoxImage.Hand);
return;
}
if (SelectedSignalCandidate == null)
{
MessageBox.Show("请先在右侧信号集合中选中一条", "提示", MessageBoxButton.OK, MessageBoxImage.Hand);
return;
}
if (string.IsNullOrWhiteSpace(SelectedSignalCandidate.SignalName) || string.IsNullOrWhiteSpace(SelectedSignalCandidate.MsgName))
{
MessageBox.Show("选中的信号数据不完整MsgName/SignalName 为空)", "提示", MessageBoxButton.OK, MessageBoxImage.Hand);
return;
}
if (ReadConfigs.Any(a => string.Equals(a.SignalName, SelectedSignalCandidate.SignalName, StringComparison.Ordinal) && a.RWInfo == RW.Read))
{
MessageBox.Show("该信号已在读取配置中,无需重复添加", "提示", MessageBoxButton.OK, MessageBoxImage.Hand);
return;
}
if (WriteConfigs.Any(a => string.Equals(a.SignalName, SelectedSignalCandidate.SignalName, StringComparison.Ordinal) && a.RWInfo == RW.Write))
{
MessageBox.Show("该信号已在写入配置中,同一个信号不允许同时配置为写入与读取", "提示", MessageBoxButton.OK, MessageBoxImage.Hand);
return;
}
ReadConfigs.Add(new CanLinRWConfigDto
{
Id = 0,
RWInfo = RW.Read,
Name = string.IsNullOrWhiteSpace(SelectedSignalCandidate.Name) ? SelectedSignalCandidate.SignalName : SelectedSignalCandidate.Name,
MsgFrameName = SelectedSignalCandidate.MsgName,
SignalName = SelectedSignalCandidate.SignalName,
DefautValue = "0",
LogicRuleId = 0,
});
RebuildSignalTree();
}
private DelegateCommand? _removeWriteCmd;
/// <summary>
/// 从写入配置移除当前选中行。
/// </summary>
public DelegateCommand RemoveWriteCmd => _removeWriteCmd ??= new DelegateCommand(RemoveWriteCmdMethod);
private void RemoveWriteCmdMethod()
{
if (!IsEditable)
{
MessageBox.Show("当前状态禁止修改", "提示", MessageBoxButton.OK, MessageBoxImage.Hand);
return;
}
if (SelectedWriteConfig == null)
{
MessageBox.Show("请先选中写入列表中的一行", "提示", MessageBoxButton.OK, MessageBoxImage.Hand);
return;
}
WriteConfigs.Remove(SelectedWriteConfig);
SelectedWriteConfig = null;
RaisePropertyChanged(nameof(SelectedWriteConfig));
RebuildSignalTree();
}
private DelegateCommand? _removeReadCmd;
/// <summary>
/// 从读取配置移除当前选中行。
/// </summary>
public DelegateCommand RemoveReadCmd => _removeReadCmd ??= new DelegateCommand(RemoveReadCmdMethod);
private void RemoveReadCmdMethod()
{
if (!IsEditable)
{
MessageBox.Show("当前状态禁止修改", "提示", MessageBoxButton.OK, MessageBoxImage.Hand);
return;
}
if (SelectedReadConfig == null)
{
MessageBox.Show("请先选中读取列表中的一行", "提示", MessageBoxButton.OK, MessageBoxImage.Hand);
return;
}
ReadConfigs.Remove(SelectedReadConfig);
SelectedReadConfig = null;
RaisePropertyChanged(nameof(SelectedReadConfig));
RebuildSignalTree();
}
private DelegateCommand? _saveCmd;
/// <summary>
/// 保存并落库。
/// </summary>
public DelegateCommand SaveCmd => _saveCmd ??= new DelegateCommand(SaveCmdMethod);
private void SaveCmdMethod()
{
if (!IsEditable)
{
MessageBox.Show("当前状态禁止修改", "提示", MessageBoxButton.OK, MessageBoxImage.Hand);
return;
}
if (_canLinConfigProId <= 0)
{
MessageBox.Show("配置程序ID无效无法保存", "提示", MessageBoxButton.OK, MessageBoxImage.Hand);
return;
}
try
{
PersistRwConfigs();
var pars = new DialogParameters
{
{ "Saved", true }
};
RaiseRequestClose(new DialogResult(ButtonResult.OK, pars));
}
catch (Exception ex)
{
_logService.Error($"ZLG 读写设置保存失败:{ex}");
MessageBox.Show(ex.Message, "错误", MessageBoxButton.OK, MessageBoxImage.Error);
}
}
private DelegateCommand? _cancelCmd;
/// <summary>
/// 取消。
/// </summary>
public DelegateCommand CancelCmd => _cancelCmd ??= new DelegateCommand(CancelCmdMethod);
private void CancelCmdMethod()
{
RaiseRequestClose(new DialogResult(ButtonResult.Cancel));
}
/// <summary>
/// 弹窗打开时接收参数。
/// </summary>
/// <param name="parameters">参数。</param>
public override void OnDialogOpened(IDialogParameters parameters)
{
_canLinConfigProId = parameters.GetValue<long>("CanLinConfigProId");
IsEditable = parameters.ContainsKey("IsEditable") ? parameters.GetValue<bool>("IsEditable") : true;
RaisePropertyChanged(nameof(IsEditable));
if (parameters.ContainsKey("WriteConfigs"))
{
var list = parameters.GetValue<ObservableCollection<CanLinRWConfigDto>>("WriteConfigs") ?? new ObservableCollection<CanLinRWConfigDto>();
WriteConfigs = list;
RaisePropertyChanged(nameof(WriteConfigs));
}
if (parameters.ContainsKey("ReadConfigs"))
{
var list = parameters.GetValue<ObservableCollection<CanLinRWConfigDto>>("ReadConfigs") ?? new ObservableCollection<CanLinRWConfigDto>();
ReadConfigs = list;
RaisePropertyChanged(nameof(ReadConfigs));
}
if (parameters.ContainsKey("SignalCandidates"))
{
var list = parameters.GetValue<ObservableCollection<SignalCandidate>>("SignalCandidates") ?? new ObservableCollection<SignalCandidate>();
SignalCandidates = list;
RaisePropertyChanged(nameof(SignalCandidates));
SignalCandidatesView = CollectionViewSource.GetDefaultView(SignalCandidates);
SignalCandidatesView.Filter = FilterSignalCandidate;
RaisePropertyChanged(nameof(SignalCandidatesView));
}
RebuildSignalTree();
if (parameters.ContainsKey("Title"))
{
Title = parameters.GetValue<string>("Title") ?? Title;
}
}
private bool FilterSignalCandidate(object obj)
{
if (obj is not SignalCandidate item)
{
return false;
}
if (string.IsNullOrWhiteSpace(SignalFilterText))
{
return true;
}
var key = SignalFilterText.Trim();
return ContainsIgnoreCase(item.MsgName, key)
|| ContainsIgnoreCase(item.SignalName, key)
|| ContainsIgnoreCase(item.Name, key)
|| ContainsIgnoreCase(item.Desc, key);
}
private void RebuildSignalTree()
{
// 依据过滤条件 + 全量候选池生成树。
// 树数据源独立于 ICollectionView避免 TreeView 过滤复杂度。
var filtered = SignalCandidates
.Where(a => FilterSignalCandidate(a))
.ToList();
var groups = filtered
.GroupBy(a => string.IsNullOrWhiteSpace(a.MsgName) ? "(未命名帧)" : a.MsgName!.Trim(), StringComparer.Ordinal)
.OrderBy(a => a.Key, StringComparer.Ordinal)
.ToList();
SignalTree.Clear();
foreach (var g in groups)
{
var signalNodes = g
.OrderBy(a => a.SignalName ?? string.Empty, StringComparer.Ordinal)
.ThenBy(a => a.Name ?? string.Empty, StringComparer.Ordinal)
.Select(a => new SignalCandidate
{
MsgName = a.MsgName,
SignalName = a.SignalName,
Name = a.Name,
Desc = a.Desc,
AddedInfo = ComputeAddedInfo(a),
})
.ToList();
var node = new SignalFrameNode
{
FrameName = g.Key,
Signals = new ObservableCollection<SignalCandidate>(signalNodes)
};
SignalTree.Add(node);
}
RaisePropertyChanged(nameof(SignalTree));
}
/// <summary>
/// 计算候选信号是否已被添加到写入/读取。
/// 0=未添加1=已添加到写入2=已添加到读取3=同时存在于写入与读取。
/// </summary>
/// <param name="candidate">候选信号。</param>
/// <returns>AddedInfo 标志值。</returns>
private int ComputeAddedInfo(SignalCandidate candidate)
{
if (candidate == null || string.IsNullOrWhiteSpace(candidate.SignalName))
{
return 0;
}
var signal = candidate.SignalName;
var inWrite = WriteConfigs.Any(a => a.RWInfo == RW.Write && string.Equals(a.SignalName, signal, StringComparison.Ordinal));
var inRead = ReadConfigs.Any(a => a.RWInfo == RW.Read && string.Equals(a.SignalName, signal, StringComparison.Ordinal));
if (inWrite && inRead) return 3;
if (inWrite) return 1;
if (inRead) return 2;
return 0;
}
private static bool ContainsIgnoreCase(string? src, string key)
{
if (string.IsNullOrEmpty(src)) return false;
return src.IndexOf(key, StringComparison.OrdinalIgnoreCase) >= 0;
}
private void PersistRwConfigs()
{
// 互斥约束:同一 SignalName 不允许同时出现在写入与读取
EnsureNoWriteReadConflict();
// 规范化 DTO空值/默认值防御)
NormalizeRwConfigs(WriteConfigs, RW.Write);
NormalizeRwConfigs(ReadConfigs, RW.Read);
// 防重复:同一 SignalName 在同一 RW 列表中只允许一条
EnsureNoDuplicateSignal(WriteConfigs, RW.Write);
EnsureNoDuplicateSignal(ReadConfigs, RW.Read);
var existing = _freeSql.Select<CanLinRWConfig>()
.Where(a => a.CanLinConfigProId == _canLinConfigProId)
.Where(a => a.RWInfo == RW.Write || a.RWInfo == RW.Read)
.ToList();
var desiredWrite = WriteConfigs
.Where(a => !string.IsNullOrWhiteSpace(a.SignalName))
.Select(a => new DesiredItem(RW.Write, a.SignalName!, a))
.ToList();
var desiredRead = ReadConfigs
.Where(a => !string.IsNullOrWhiteSpace(a.SignalName))
.Select(a => new DesiredItem(RW.Read, a.SignalName!, a))
.ToList();
var desiredAll = desiredWrite.Concat(desiredRead).ToList();
var desiredKeySet = new HashSet<string>(desiredAll.Select(a => BuildKey(a.Rw, a.SignalName)), StringComparer.Ordinal);
var existingByKey = existing.ToDictionary(a => BuildKey(a.RWInfo, a.SignalName ?? string.Empty), a => a, StringComparer.Ordinal);
// 删除DB 中存在,但目标集合里不存在
foreach (var old in existing)
{
var key = BuildKey(old.RWInfo, old.SignalName ?? string.Empty);
if (!desiredKeySet.Contains(key))
{
_freeSql.Delete<CanLinRWConfig>(old.Id).ExecuteAffrows();
}
}
// Upsert按 keyRWInfo + SignalName更新或插入
foreach (var item in desiredAll)
{
var key = BuildKey(item.Rw, item.SignalName);
if (existingByKey.TryGetValue(key, out var old))
{
_freeSql.Update<CanLinRWConfig>(old.Id)
.Set(a => a.Name, item.Dto.Name)
.Set(a => a.MsgFrameName, item.Dto.MsgFrameName)
.Set(a => a.SignalName, item.Dto.SignalName)
.Set(a => a.DefautValue, item.Dto.DefautValue)
.Set(a => a.LogicRuleId, item.Dto.LogicRuleId)
.ExecuteAffrows();
}
else
{
_freeSql.Insert<CanLinRWConfig>(new CanLinRWConfig
{
CanLinConfigProId = _canLinConfigProId,
RWInfo = item.Rw,
Name = item.Dto.Name,
MsgFrameName = item.Dto.MsgFrameName,
SignalName = item.Dto.SignalName,
DefautValue = item.Dto.DefautValue,
LogicRuleId = item.Dto.LogicRuleId,
}).ExecuteAffrows();
}
}
}
private static void NormalizeRwConfigs(IEnumerable<CanLinRWConfigDto> list, RW rw)
{
foreach (var item in list)
{
item.RWInfo = rw;
if (string.IsNullOrWhiteSpace(item.SignalName))
{
continue;
}
if (string.IsNullOrWhiteSpace(item.Name))
{
item.Name = item.SignalName;
}
if (string.IsNullOrWhiteSpace(item.MsgFrameName))
{
item.MsgFrameName = string.Empty;
}
if (string.IsNullOrWhiteSpace(item.DefautValue))
{
item.DefautValue = "0";
}
if (item.LogicRuleId < 0)
{
item.LogicRuleId = 0;
}
}
}
private static void EnsureNoDuplicateSignal(IEnumerable<CanLinRWConfigDto> list, RW rw)
{
var duplicates = list
.Where(a => !string.IsNullOrWhiteSpace(a.SignalName))
.GroupBy(a => a.SignalName!, StringComparer.Ordinal)
.Where(g => g.Count() > 1)
.Select(g => g.Key)
.ToList();
if (duplicates.Count > 0)
{
throw new InvalidOperationException($"{rw} 配置中存在重复信号:{string.Join(",", duplicates)}");
}
}
private void EnsureNoWriteReadConflict()
{
var writeSet = new HashSet<string>(
WriteConfigs
.Where(a => a.RWInfo == RW.Write)
.Select(a => a.SignalName)
.Where(a => !string.IsNullOrWhiteSpace(a))
.Select(a => a!),
StringComparer.Ordinal);
var readSet = new HashSet<string>(
ReadConfigs
.Where(a => a.RWInfo == RW.Read)
.Select(a => a.SignalName)
.Where(a => !string.IsNullOrWhiteSpace(a))
.Select(a => a!),
StringComparer.Ordinal);
writeSet.IntersectWith(readSet);
if (writeSet.Count > 0)
{
throw new InvalidOperationException($"同一信号不允许同时配置为写入与读取,冲突信号:{string.Join(",", writeSet)}");
}
}
private static string BuildKey(RW rw, string signalName)
{
return $"{(int)rw}:{signalName}";
}
private readonly struct DesiredItem
{
/// <summary>
/// 读写类型。
/// </summary>
public RW Rw { get; }
/// <summary>
/// 信号名称。
/// </summary>
public string SignalName { get; }
/// <summary>
/// 原始 DTO。
/// </summary>
public CanLinRWConfigDto Dto { get; }
public DesiredItem(RW rw, string signalName, CanLinRWConfigDto dto)
{
Rw = rw;
SignalName = signalName;
Dto = dto;
}
}
/// <summary>
/// 右侧信号候选项。
/// </summary>
public class SignalCandidate
{
/// <summary>
/// 消息名称/帧名称。
/// </summary>
public string? MsgName { get; set; }
/// <summary>
/// 信号名称。
/// </summary>
public string? SignalName { get; set; }
/// <summary>
/// 配置名称(若解析层已有中文名则传入)。
/// </summary>
public string? Name { get; set; }
/// <summary>
/// 描述。
/// </summary>
public string? Desc { get; set; }
/// <summary>
/// 已添加标记。
/// 0=未添加1=已添加到写入2=已添加到读取3=同时存在于写入与读取。
/// </summary>
public int AddedInfo { get; set; }
}
/// <summary>
/// 帧节点。
/// </summary>
public class SignalFrameNode
{
/// <summary>
/// 帧名。
/// </summary>
public string FrameName { get; set; } = string.Empty;
/// <summary>
/// 帧内信号集合。
/// </summary>
public ObservableCollection<SignalCandidate> Signals { get; set; } = new ObservableCollection<SignalCandidate>();
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -4,6 +4,7 @@ using CapMachine.Model.CANLIN;
using CapMachine.Wpf.Dtos;
using CapMachine.Wpf.LinDrive;
using CapMachine.Wpf.Services;
using CapMachine.Wpf.Views;
using ImTools;
using Microsoft.Win32;
using Prism.Commands;
@@ -78,6 +79,25 @@ namespace CapMachine.Wpf.ViewModels
/// </summary>
public CanLinConfigPro? SelectCanLinConfigPro { get; set; }
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(); }
}
public bool IsRwEditable
{
get { return !ZlgLinDriveService.OpenState; }
}
private LINConfigExdDto? _SelectedLINConfigExdDto;
/// <summary>
/// 选中的 LIN 配置 DTO。
@@ -146,6 +166,14 @@ namespace CapMachine.Wpf.ViewModels
{
if (SelectCanLinConfigPro == null) return;
SelectedLINConfigExdDto = Mapper.Map<LINConfigExdDto>(SelectCanLinConfigPro.LINConfigExd);
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));
RaisePropertyChanged(nameof(IsRwEditable));
}
private DelegateCommand<object>? _LinConfigProGridSelectionChangedCmd;
@@ -270,11 +298,15 @@ namespace CapMachine.Wpf.ViewModels
{
ConfigService.CanLinRunStateModel.CurSysSelectedCanLin = CanLinEnum.Lin;
}
RaisePropertyChanged(nameof(IsRwEditable));
break;
case "Close":
ZlgLinDriveService.CloseDevice();
ConfigService.CanLinRunStateModel.CurSysSelectedCanLin = CanLinEnum.No;
RaisePropertyChanged(nameof(IsRwEditable));
break;
case "Save":
@@ -315,6 +347,113 @@ namespace CapMachine.Wpf.ViewModels
}
}
private DelegateCommand? _openRwDialogCmd;
public DelegateCommand OpenRwDialogCmd
{
get
{
if (_openRwDialogCmd == null)
{
_openRwDialogCmd = new DelegateCommand(OpenRwDialogCmdMethod);
}
return _openRwDialogCmd;
}
}
private void OpenRwDialogCmdMethod()
{
try
{
if (SelectCanLinConfigPro == null)
{
MessageBox.Show("选中LIN配置名称后再操作", "提示", 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 (ZlgLinDriveService.ListLinLdfModel != null)
{
foreach (var sig in ZlgLinDriveService.ListLinLdfModel)
{
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();
}
});
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "错误", MessageBoxButton.OK, MessageBoxImage.Error);
}
}
private void ReloadCurrentConfigPro()
{
var id = SelectCanLinConfigPro?.Id;
InitLoadLinConfigPro();
if (id != null)
{
SelectCanLinConfigPro = linConfigPros.Find(a => a.Id == id.Value);
SyncSelectedConfig();
}
}
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,
};
}
private DelegateCommand<object>? _SchEnableCmd;
/// <summary>
/// 调度表使能写入驱动。