using JinYuan.Models; using JinYuan.VirtualDataLibrary; using Language; using MiniExcelLibs; using System; using System.Collections.Generic; using System.Data; using System.Drawing; using System.IO; using System.Linq; using System.Windows.Forms; namespace LargeSquareOne { public partial class CommunicationEditForm : MultiLanguageForm { private string groupPath = CommonMethods.groupConfigPath; //Application.StartupPath + $"\\Config\\Group_{CommonMethods.sysConfig.StationNo}.xlsx"; private List TotalGroups = new List(); private PlcGroupConfig editingConfig; private int PlcNum; public CommunicationEditForm(int plcNum) { PlcNum = plcNum; InitializeComponent(); this.groupTable.AutoGenerateColumns = false; InitializeDataGridView(); TotalGroups = GetALLGroups(); LoadGroups(); } /// /// 初始化DataGridView /// private void InitializeDataGridView() { groupTable.AutoGenerateColumns = false; groupTable.AllowUserToAddRows = false; groupTable.SelectionMode = DataGridViewSelectionMode.FullRowSelect; groupTable.MultiSelect = false; groupTable.ReadOnly = false; // 添加列 groupTable.Columns.AddRange(new DataGridViewColumn[] { new DataGridViewTextBoxColumn { Name = "PlcNum", HeaderText = "PLC编号", Width = 120, ReadOnly = true, DataPropertyName = "PlcNum", DefaultCellStyle = new DataGridViewCellStyle(){Alignment=DataGridViewContentAlignment.MiddleCenter}, Frozen = true }, new DataGridViewTextBoxColumn { Name = "GroupName", HeaderText = "组名", Width = 120, DataPropertyName = "GroupName", DefaultCellStyle = new DataGridViewCellStyle(){Alignment=DataGridViewContentAlignment.MiddleCenter}, Frozen = true }, new DataGridViewTextBoxColumn { Name = "Start", HeaderText = "起始地址", Width = 150, DataPropertyName = "Start", DefaultCellStyle = new DataGridViewCellStyle(){Alignment=DataGridViewContentAlignment.MiddleCenter}, Frozen = true }, new DataGridViewTextBoxColumn { Name = "Length", HeaderText = "长度", Width = 120, DataPropertyName = "Length", DefaultCellStyle = new DataGridViewCellStyle(){Alignment=DataGridViewContentAlignment.MiddleCenter}, }, new DataGridViewCheckBoxColumn { Name = "IsTiggerRead", HeaderText = "触发读取", Width = 150, DataPropertyName = "IsTiggerRead", DefaultCellStyle = new DataGridViewCellStyle(){Alignment=DataGridViewContentAlignment.MiddleCenter}, }, new DataGridViewCheckBoxColumn { Name = "IsFeedbackPlc", HeaderText = "反馈PLC", Width = 150, DataPropertyName = "IsFeedbackPlc", DefaultCellStyle = new DataGridViewCellStyle(){Alignment=DataGridViewContentAlignment.MiddleCenter}, }, new DataGridViewCheckBoxColumn { Name = "IsActive", HeaderText = "是否启用", Width = 150, DataPropertyName = "IsActive", DefaultCellStyle = new DataGridViewCellStyle(){Alignment=DataGridViewContentAlignment.MiddleCenter}, }, new DataGridViewTextBoxColumn { Name = "Remark", HeaderText = "备注", Width = 150, DataPropertyName = "Remark", Visible=false, DefaultCellStyle = new DataGridViewCellStyle(){Alignment=DataGridViewContentAlignment.MiddleCenter}, }, new DataGridViewButtonColumn { Name = "Edit", HeaderText = "操作", Width = 100, Text = "修改".Translated(), UseColumnTextForButtonValue = true }, new DataGridViewButtonColumn { Name = "Delete", HeaderText = "", Width = 100, Text = "删除".Translated(), UseColumnTextForButtonValue = true } }); // 添加事件处理 groupTable.CellBeginEdit += DataGridView_CellBeginEdit; groupTable.CellEndEdit += DataGridView_CellEndEdit; groupTable.CellContentClick += DataGridView_CellContentClick; } /// /// 加载数据到表格 /// private void LoadGroups() { var plcGroups = TotalGroups.Where(g => g.PlcNum == PlcNum).ToList(); groupTable.DataSource = null; groupTable.DataSource = plcGroups; } /// /// 获取所有通信组 /// /// private List GetALLGroups() { try { return MiniExcel.Query(groupPath).ToList(); } catch (Exception) { return new List(); } } /// /// 单元格开始编辑 /// private void DataGridView_CellBeginEdit(object sender, DataGridViewCellCancelEventArgs e) { if (e.RowIndex < 0) return; // 获取当前行显示的数据 var currentRow = groupTable.Rows[e.RowIndex]; var config = (PlcGroupConfig)currentRow.DataBoundItem; editingConfig = TotalGroups.First(g => g.PlcNum == config.PlcNum && g.GroupName == config.GroupName && g.Start == config.Start); // 禁止编辑PLC编号和组名列 if (groupTable.Columns[e.ColumnIndex].Name == "PlcNum") { e.Cancel = true; } } /// /// 单元格结束编辑 /// private void DataGridView_CellEndEdit(object sender, DataGridViewCellEventArgs e) { if (e.RowIndex < 0 || e.RowIndex >= TotalGroups.Count) return; // 获取当前行显示的数据 var currentRow = groupTable.Rows[e.RowIndex]; var curConfig = (PlcGroupConfig)currentRow.DataBoundItem; var config = TotalGroups.First(g => g.PlcNum == curConfig.PlcNum && g.GroupName == curConfig.GroupName && g.Start == curConfig.Start); var value = groupTable[e.ColumnIndex, e.RowIndex].Value; try { UpdateConfigValue(config, e.ColumnIndex, value); } catch (Exception ex) { ShowError($"更新数据失败: {ex.Message}"); } } /// /// 更新配置值 /// private void UpdateConfigValue(PlcGroupConfig config, int columnIndex, object value) { switch (groupTable.Columns[columnIndex].Name) { case "GroupName": if (string.IsNullOrWhiteSpace(value?.ToString())) { throw new Exception("组名不能为空".Translated()); } config.GroupName = value.ToString(); break; case "Start": if (!ValidateAddressFormat(value?.ToString())) { throw new Exception("起始地址格式不正确".Translated()); } config.Start = value.ToString(); break; case "Length": if (!int.TryParse(value?.ToString(), out int length) || length <= 0) { throw new Exception("长度必须是大于0的数字".Translated()); } config.Length = length; break; case "IsTiggerRead": config.IsTiggerRead = value != null && (bool)value; break; case "IsFeedbackPlc": config.IsFeedbackPlc = value != null && (bool)value; break; case "IsActive": config.IsActive = value != null && (bool)value; break; case "Remark": config.Remark = value?.ToString() ?? string.Empty; break; } } /// /// 单元格点击事件 /// private void DataGridView_CellContentClick(object sender, DataGridViewCellEventArgs e) { if (e.RowIndex < 0) return; // 获取当前行显示的数据 var currentRow = groupTable.Rows[e.RowIndex]; var config = (PlcGroupConfig)currentRow.DataBoundItem; // 找到在 TotalGroups 中的真实索引 var realIndex = TotalGroups.FindIndex(g => g.PlcNum == config.PlcNum && g.GroupName == config.GroupName && g.Start == config.Start); // 编辑按钮 if (groupTable.Columns[e.ColumnIndex] is DataGridViewButtonColumn && groupTable.Columns[e.ColumnIndex].Name == "Edit") { // 传递真实的索引,而不是显示的行索引 HandleEdit(config, realIndex); } // 删除按钮 else if (groupTable.Columns[e.ColumnIndex] is DataGridViewButtonColumn && groupTable.Columns[e.ColumnIndex].Name == "Delete") { HandleDelete(config); } } /// /// 处理编辑操作 /// private void HandleEdit(PlcGroupConfig config, int rowIndex) { try { var result = MessageBox.Show("是否保存修改的配置?".Translated(), "确认保存".Translated(), MessageBoxButtons.YesNo, MessageBoxIcon.Question); if (result != DialogResult.Yes) return; if (!ValidateConfigAll(config)) return; // 更新TotalGroups中的配置 TotalGroups[rowIndex] = config; // 保存到Excel SaveToExcel(TotalGroups); // 重新加载显示 LoadGroups(); ShowSuccess("配置保存成功".Translated()); } catch (Exception ex) { ShowError($"保存失败: {ex.Message}"); } } /// /// 处理删除操作 /// private void HandleDelete(PlcGroupConfig config) { var result = MessageBox.Show($"确定要删除该通信组吗?\n PLC编号[{config.PlcNum}] 组名: [{config.GroupName}]", "确认删除", MessageBoxButtons.YesNo, MessageBoxIcon.Question); if (result == DialogResult.Yes) { try { TotalGroups.Remove(config); SaveToExcel(TotalGroups); LoadGroups(); ShowSuccess("删除成功".Translated()); } catch (Exception ex) { ShowError($"删除失败: {ex.Message}"); } } } /// /// 保存配置到Excel文件 /// private void SaveToExcel(List configs) { try { // 创建临时文件路径 string tempFilePath = Path.Combine( Path.GetDirectoryName(groupPath), $"temp_{Path.GetFileName(groupPath)}"); // 先保存到临时文件 MiniExcel.SaveAs(tempFilePath, configs); // 检查临时文件是否创建成功 if (!File.Exists(tempFilePath)) { throw new Exception("创建临时文件失败".Translated()); } try { // 如果原文件存在,先删除 if (File.Exists(groupPath)) { File.Delete(groupPath); } // 将临时文件重命名为目标文件 File.Move(tempFilePath, groupPath); } finally { // 确保临时文件被删除 if (File.Exists(tempFilePath)) { File.Delete(tempFilePath); } } } catch (Exception ex) { throw new Exception($"保存Excel文件时发生错误: {ex.Message}", ex); } } /// /// 验证单行配置 /// private bool ValidateConfigAll(PlcGroupConfig config) { try { // 基本字段验证 if (string.IsNullOrWhiteSpace(config.GroupName)) { ShowError("组名不能为空".Translated()); return false; } if (string.IsNullOrWhiteSpace(config.Start)) { ShowError("起始地址不能为空".Translated()); return false; } if (config.Length <= 0) { ShowError("长度必须大于0".Translated()); return false; } // 地址格式验证 if (!ValidateAddressFormat(config.Start)) { ShowError("起始地址格式不正确,应以'D'开头后跟数字".Translated()); return false; } // 打印调试信息 Console.WriteLine($"当前要添加的配置 - PLC号: {config.PlcNum}, 组名: {config.GroupName}"); //// 打印所有的配置 //Console.WriteLine("\n所有配置信息:"); //foreach (var g in TotalGroups) //{ // Console.WriteLine($"PLC号: {g.PlcNum}, 组名: {g.GroupName}"); //} // 筛选同PLC的配置(不包括当前正在添加的配置) var groupsInSamePLC = TotalGroups.Where(g => g.PlcNum == config.PlcNum && // 筛选 PLC1 的配置 g != config // 这个条件是需要的,因为可能当前配置已经在集合中 ).ToList(); // 允许同一个PLC内有多个相同的组名 by clm 20260804 // 3. 只在同一个PLC内检查地址是否冲突 //if (groupsInSamePLC.Any(g => g.GroupName.Equals(config.GroupName, StringComparison.OrdinalIgnoreCase))) //{ // ShowError($"在PLC {config.PlcNum} 中,组名 {config.GroupName} 已被使用"); // return false; //} //Console.WriteLine("\n筛选后的配置:"); //foreach (var g in groupsInSamePLC) //{ // Console.WriteLine($"PLC号: {g.PlcNum}, 组名: {g.GroupName}"); //} // 3. 只在同一个PLC内检查地址是否冲突 if (groupsInSamePLC.Any(g => g.Start.Equals(config.Start, StringComparison.OrdinalIgnoreCase))) { ShowError($"在PLC {config.PlcNum} 中,起始地址 {config.Start} 已被使用"); return false; } // 地址范围验证 int startAddress = int.Parse(config.Start.Substring(1)); int endAddress = startAddress + config.Length - 1; if (endAddress > 32675) { ShowError($"地址范围超出限制,结束地址不能超过D32675".Translated()); return false; } // 取消该检查 by clm 20260804 // 检查地址范围冲突 //foreach (var other in groupsInSamePLC) //{ // int otherStart = int.Parse(other.Start.Substring(1)); // int otherEnd = otherStart + other.Length - 1; // if (!(endAddress < otherStart || startAddress > otherEnd)) // { // ShowError($"地址范围与组 \"{other.GroupName}\" 冲突"); // return false; // } //} return true; } catch (Exception ex) { ShowError($"验证配置时发生错误: {ex.Message}"); return false; } } // 地址格式验证 private bool ValidateAddressFormat(string address) { if (string.IsNullOrWhiteSpace(address)) return false; // 检查是否以D开头(不区分大小写) if (!address.StartsWith("D", StringComparison.OrdinalIgnoreCase)) { return false; } // 检查后面是否为有效数字 string numberPart = address.Substring(1); if (!int.TryParse(numberPart, out int addressNum)) { return false; } // 检查地址范围(根据实际需求调整范围) if (addressNum < 0 || addressNum > 30000) { return false; } return true; } #region 添加新通信组 /// /// 添加新通信组 /// /// /// private void BtnAdd_Click(object sender, EventArgs e) { try { // 创建新组配置 var newGroup = new PlcGroupConfig { PlcNum = PlcNum, // 使用当前PlcNum而不是CurrentPLCConfig.PlcNum GroupName = GenerateNewGroupName(), Start = FindNextAvailableAddress(), Length = 100, IsTiggerRead = true, IsFeedbackPlc = true, IsActive = true, Remark = "" }; // 验证新配置 if (!ValidateConfigAll(newGroup)) { return; } // 添加到总配置列表 TotalGroups.Add(newGroup); // 保存到Excel文件 SaveToExcel(TotalGroups); // 重新加载显示 LoadGroups(); ShowSuccess("新建通信组成功".Translated()); } catch (Exception ex) { ShowError($"添加通信组失败: {ex.Message}"); } } /// /// 生成新的组名 /// private string GenerateNewGroupName() { int index = 1; string baseName = "新建组".Translated(); string newName = baseName; // 查找可用的组名 while (TotalGroups.Any(g => g.PlcNum == PlcNum && g.GroupName.Equals(newName, StringComparison.OrdinalIgnoreCase))) { index++; newName = $"{baseName}{index}"; } return newName; } /// /// 查找下一个可用的地址 /// private string FindNextAvailableAddress() { // 获取当前PLC的所有组 var plcGroups = TotalGroups.Where(g => g.PlcNum == PlcNum && g.IsActive).ToList(); if (!plcGroups.Any()) { return "D0"; // 如果没有现有组,从D0开始 } // 找到最大的结束地址 int maxEndAddress = plcGroups.Max(g => { int startAddr = int.Parse(g.Start.Substring(1)); return startAddr + g.Length; }); // 确保地址不超过最大限制(32675) if (maxEndAddress >= 32675) { throw new Exception("没有可用的地址空间".Translated()); } // 返回下一个可用地址 return $"D{maxEndAddress}"; } /// /// 查找地址间隔 /// private string FindAddressGap(int requiredLength = 100) { // 获取当前PLC的所有组,并按起始地址排序 var plcGroups = TotalGroups .Where(g => g.PlcNum == PlcNum) .Select(g => new { Start = int.Parse(g.Start.Substring(1)), End = int.Parse(g.Start.Substring(1)) + g.Length - 1 }) .OrderBy(g => g.Start) .ToList(); // 如果没有组,返回起始地址 if (!plcGroups.Any()) { return "D0"; } // 检查第一个组之前是否有足够空间 if (plcGroups.First().Start >= requiredLength) { return "D0"; } // 检查组之间的间隔 for (int i = 0; i < plcGroups.Count - 1; i++) { int gapStart = plcGroups[i].End + 1; int gapEnd = plcGroups[i + 1].Start - 1; if (gapEnd - gapStart + 1 >= requiredLength) { return $"D{gapStart}"; } } // 检查最后一个组之后是否有足够空间 int lastEnd = plcGroups.Last().End; if (lastEnd + requiredLength <= 32675) { return $"D{lastEnd + 1}"; } throw new Exception("没有找到足够大的地址空间".Translated()); } private void btn_Close_Click(object sender, EventArgs e) { this.Close(); } #endregion // 错误提示 private void ShowError(string message) { MessageBox.Show(message, "验证错误".Translated(), MessageBoxButtons.OK, MessageBoxIcon.Error); } // 成功提示 private void ShowSuccess(string message) { MessageBox.Show(message, "成功".Translated(), MessageBoxButtons.OK, MessageBoxIcon.Information); } #region 无边框拖动 private Point mPoint; private void Panel_MouseDown(object sender, MouseEventArgs e) { mPoint = new Point(e.X, e.Y); } private void Panel_MouseMove(object sender, MouseEventArgs e) { if (e.Button == MouseButtons.Left) { this.Location = new Point(this.Location.X + e.X - mPoint.X, this.Location.Y + e.Y - mPoint.Y); } } #endregion #region 减少闪烁 protected override CreateParams CreateParams { get { CreateParams cp = base.CreateParams; cp.ExStyle |= 0x02000000; return cp; } } #endregion } }