using AutoMapper; using CapMachine.Core; using CapMachine.Model; using CapMachine.Model.CANLIN; using CapMachine.Wpf.Dtos; using CapMachine.Wpf.Services; using ImTools; using Prism.Commands; using Prism.Services.Dialogs; using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows; namespace CapMachine.Wpf.ViewModels { /// /// ZLG CAN 调度表配置 /// public class DialogZlgCANSchConfigViewModel : DialogViewModel { /// /// 构造函数 /// public DialogZlgCANSchConfigViewModel(IFreeSql freeSql, IMapper mapper) { Title = "调度表 CAN 配置"; FreeSql = freeSql; Mapper = mapper; SendOrderCbxItems = new ObservableCollection() { new CbxItems(){ Key="0", Text="并行", }, new CbxItems(){ Key="1", Text="顺序", }, }; //默认只能用1号调度器 SchTabIndexCbxItems = new ObservableCollection() { new CbxItems(){ Key="0", Text="0", }, //new CbxItems(){ // Key="1", // Text="1", //}, //new CbxItems(){ // Key="2", // Text="2", //}, //new CbxItems(){ // Key="3", // Text="3", //}, //new CbxItems(){ // Key="4", // Text="4", //}, }; } /// /// FreeSql(用于调度表项的删除/保存落库)。 /// public IFreeSql FreeSql { get; } /// /// AutoMapper(DTO 与实体映射)。 /// public IMapper Mapper { get; } private string name; /// /// 名称 /// public string Name { get { return name; } set { name = value; RaisePropertyChanged(); } } private ObservableCollection _ListCANScheduleConfigDto = new ObservableCollection(); /// /// CAN 调度表数据集合 /// public ObservableCollection ListCANScheduleConfigDto { get { return _ListCANScheduleConfigDto; } set { _ListCANScheduleConfigDto = value; RaisePropertyChanged(); } } /// /// 消息/帧报文信息集合 /// public List? ListMsg { get; set; } private ObservableCollection _MsgCbxItems; /// /// 消息名称 集合信息 /// public ObservableCollection MsgCbxItems { get { return _MsgCbxItems; } set { _MsgCbxItems = value; RaisePropertyChanged(); } } /// /// 选中的程序的Id /// public long SelectCanLinConfigProId { get; set; } private ObservableCollection _SendOrderCbxItems; /// /// 发送方式 集合信息 /// public ObservableCollection SendOrderCbxItems { get { return _SendOrderCbxItems; } set { _SendOrderCbxItems = value; RaisePropertyChanged(); } } private string? _CurSendOrder; /// /// 当前发送方式 /// public string? CurSendOrder { get { return _CurSendOrder; } set { _CurSendOrder = value; RaisePropertyChanged(); } } private ObservableCollection _SchTabIndexCbxItems; /// /// 调度器序号 集合信息 /// public ObservableCollection SchTabIndexCbxItems { get { return _SchTabIndexCbxItems; } set { _SchTabIndexCbxItems = value; RaisePropertyChanged(); } } private CANScheduleConfigDto _CurSelectedItem; /// /// 当前选中的调度表项(用于删除等操作)。 /// public CANScheduleConfigDto CurSelectedItem { get { return _CurSelectedItem; } set { _CurSelectedItem = value; RaisePropertyChanged(); } } private DelegateCommand _GridSelectionChangedCmd; /// /// DataGrid 选中行变化。 /// public DelegateCommand GridSelectionChangedCmd { set { _GridSelectionChangedCmd = value; } get { if (_GridSelectionChangedCmd == null) { _GridSelectionChangedCmd = new DelegateCommand((par) => GridSelectionChangedCmdMethod(par)); } return _GridSelectionChangedCmd; } } private void GridSelectionChangedCmdMethod(object par) { // 先判断是否是正确的集合数据,防止 DataGrid 的 ItemsSource 刷新导致的误触发。 var Selecteddata = par as CANScheduleConfigDto; if (Selecteddata != null) { CurSelectedItem = Selecteddata; } } private DelegateCommand _OpCmd; /// /// 操作命令(删除)。 /// 说明:新增调度表项由“读写设置”弹窗内的“加入定时调度表”生成,此处仅允许删除与保存。 /// public DelegateCommand OpCmd { set { _OpCmd = value; } get { if (_OpCmd == null) { _OpCmd = new DelegateCommand((Par) => OpCmdCall(Par)); } return _OpCmd; } } private void OpCmdCall(string Par) { switch (Par) { case "Add": MessageBox.Show("调度表项由【读写设置】中的写入配置通过“加入定时调度表”生成,这里不支持新增。", "提示", MessageBoxButton.OK, MessageBoxImage.Hand); break; case "Delete": if (CurSelectedItem != null) { // 直接落库删除(无论 UI 是否还有引用,都以数据库为准)。 FreeSql.Delete(CurSelectedItem.Id).ExecuteAffrows(); ListCANScheduleConfigDto.Remove(CurSelectedItem); CurSelectedItem = null; } else { MessageBox.Show("请选中后再进行【删除】操作?", "提示", MessageBoxButton.OK, MessageBoxImage.Hand); } break; default: break; } } private DelegateCommand saveCmd; /// /// 保存命令 /// public DelegateCommand SaveCmd { set { saveCmd = value; } get { if (saveCmd == null) { saveCmd = new DelegateCommand(() => SaveCmdMethod()); } return saveCmd; } } /// /// 保存命令方法。 /// 说明: /// - 先做必要校验(MsgName/Cycle/发送方式等),避免写入无效配置; /// - 使用 InsertOrUpdate 保证“新增/修改”统一处理; /// - 保存完成后重新从数据库加载,作为最终权威数据,并通过 DialogResult 回传给调用方。 /// private void SaveCmdMethod() { // 校验:确保每个调度项具备最小可用字段。 foreach (var item in ListCANScheduleConfigDto) { // UI 上的“发送方式”是全局下拉框,这里同步写回到每个子项,确保落库数据一致。 item.OrderSend = CurSendOrder == "0" ? 0 : 1; if (string.IsNullOrEmpty(item.MsgName)) { MessageBox.Show("消息名为空:请在【读写设置】-> 写入配置中选择报文后点击“加入定时调度表”,再回到此处设置周期。", "提示", MessageBoxButton.OK, MessageBoxImage.Hand); return; } if (item.Cycle <= 0) { MessageBox.Show("请确认周期是否正确", "提示", MessageBoxButton.OK, MessageBoxImage.Hand); return; } if (item.OrderSend >= 2) { MessageBox.Show("请确认发送方式是否正确", "提示", MessageBoxButton.OK, MessageBoxImage.Hand); return; } } //发送的控制帧都放到同一个调度表中,不需要检查了 ////检查重复设置问题 //bool isRepeat = ListCANScheduleConfigDto.GroupBy(i => i.MsgName).Any(g => g.Count() > 1); //if (isRepeat) //{ // MessageBox.Show("请确认是否重复设置", "提示", MessageBoxButton.OK, MessageBoxImage.Hand); // return; //} // Upsert:逐项落库。 foreach (var item in ListCANScheduleConfigDto) { FreeSql.InsertOrUpdate() .SetSource(Mapper.Map(item)). ExecuteAffrows(); } // 保存完成后重新加载: // - 防止 UI 缓存与数据库实际数据不一致; // - 同时也让新增项拿到真实 Id。 ListCANScheduleConfigDto = new ObservableCollection(Mapper.Map>(FreeSql.Select().Where(a => a.CanLinConfigProId == SelectCanLinConfigProId).ToList())); DialogParameters pars = new DialogParameters { { "ReturnValue", ListCANScheduleConfigDto } }; RaiseRequestClose(new DialogResult(ButtonResult.OK, pars)); } private DelegateCommand cancelCmd; /// /// 取消命令。 /// public DelegateCommand CancelCmd { set { cancelCmd = value; } get { if (cancelCmd == null) { cancelCmd = new DelegateCommand(() => CancelCmdMethod()); } return cancelCmd; } } /// /// 取消命令方法。 /// private void CancelCmdMethod() { RaiseRequestClose(new DialogResult(ButtonResult.Cancel)); } /// /// 弹窗打开时接收参数并初始化 UI。 /// 说明: /// - ListMsg 用于构造消息名下拉框; /// - ListCANScheduleConfigDto 用于回显现有调度表; /// - SelectCanLinConfigProId 用于 Save 时按配置程序 id 过滤重载。 /// /// public override void OnDialogOpened(IDialogParameters parameters) { if (parameters.ContainsKey("ListMsg")) { ListMsg = parameters.GetValue>("ListMsg"); if (ListMsg != null) { // 转换为CbxItems集合,都是文本内容 MsgCbxItems = new ObservableCollection( ListMsg.Select(value => new CbxItems { Key = value, Text = value })); } } ListCANScheduleConfigDto = parameters.GetValue>("ListCANScheduleConfigDto"); //防止返回的数据为空,就无法增加了 if (ListCANScheduleConfigDto == null) ListCANScheduleConfigDto = new ObservableCollection(); //Name = parameters.GetValue("Name"); if (ListCANScheduleConfigDto.Count > 0) { // 回显:默认取第一条的 OrderSend 作为当前下拉框选择。 CurSendOrder = ListCANScheduleConfigDto.FirstOrDefault()!.OrderSend.ToString(); } else { // 默认:顺序发送。 CurSendOrder = "1"; } SelectCanLinConfigProId = parameters.GetValue("SelectCanLinConfigProId"); } } }