using HMI.UI.Util;
|
using Panuon.WPF.UI;
|
using Plugin.DeviceConfig.Entity;
|
using Plugin.DeviceConfig.Model;
|
using System;
|
using System.Collections.ObjectModel;
|
using System.Linq;
|
using System.Windows;
|
using System.Windows.Controls;
|
|
namespace Plugin.DeviceConfig
|
{
|
/// <summary>
|
/// DeviceEditModal.xaml 的交互逻辑
|
/// </summary>
|
public partial class DeviceEditModal : WindowX
|
{
|
private DeviceConfigModel _model;
|
private DeviceDefinition _device;
|
private ObservableCollection<DeviceChannel> _channels = new();
|
private bool _isNew;
|
|
public DeviceEditModal()
|
{
|
DataContext = this;
|
InitializeComponent();
|
}
|
|
/// <summary>
|
/// 打开弹窗
|
/// </summary>
|
public bool? Open(DeviceDefinition device, DeviceConfigModel model)
|
{
|
_model = model;
|
_device = device;
|
_isNew = string.IsNullOrEmpty(device.DeviceId);
|
|
// 初始化枚举下拉
|
cbKind.ItemsSource = Enum.GetValues(typeof(DeviceKind)).Cast<DeviceKind>().ToList();
|
cbTransport.ItemsSource = Enum.GetValues(typeof(TransportType)).Cast<TransportType>().ToList();
|
cbTransport.SelectionChanged += CbTransport_SelectionChanged;
|
|
// 填充数据
|
tbDeviceId.Text = device.DeviceId;
|
tbDeviceId.IsReadOnly = !_isNew;
|
cbKind.SelectedItem = device.Kind;
|
tbDriverType.Text = device.DriverType;
|
cbTransport.SelectedItem = device.Transport;
|
tbEndpoint.Text = device.Endpoint;
|
|
// 默认驱动类型建议 & 端点提示
|
UpdateDriverHint();
|
UpdateEndpointHint();
|
|
// 加载通道
|
if (!_isNew && !string.IsNullOrEmpty(device.DeviceId))
|
{
|
var chList = _model.GetChannelsByDevice(device.DeviceId);
|
_channels = new ObservableCollection<DeviceChannel>(chList);
|
}
|
else
|
{
|
_channels = new ObservableCollection<DeviceChannel>();
|
}
|
channelListView.ItemsSource = _channels;
|
|
return ShowDialog();
|
}
|
|
#region 通道操作
|
|
private void AddChannel_Click(object sender, RoutedEventArgs e)
|
{
|
try
|
{
|
if (!int.TryParse(tbChId.Text, out int chId) || chId < 0)
|
{
|
ToastHelper.Warning("请输入有效的通道编号(非负整数)");
|
return;
|
}
|
if (_channels.Any(c => c.ChannelId == chId))
|
{
|
ToastHelper.Warning($"通道 {chId} 已存在");
|
return;
|
}
|
|
double.TryParse(tbChVolt.Text, out double volt);
|
double.TryParse(tbChCurr.Text, out double curr);
|
|
var ch = new DeviceChannel
|
{
|
DeviceId = _device.DeviceId ?? tbDeviceId.Text,
|
ChannelId = chId,
|
Capability = tbChCap.Text ?? string.Empty,
|
MaxVoltage = volt,
|
MaxCurrent = curr,
|
};
|
_channels.Add(ch);
|
ClearChannelInputs();
|
}
|
catch (Exception ex)
|
{
|
ToastHelper.Error($"新增通道失败: {ex.Message}");
|
}
|
}
|
|
private void EditChannel_Click(object sender, RoutedEventArgs e)
|
{
|
try
|
{
|
if (sender is Button btn && btn.Tag is DeviceChannel ch)
|
{
|
tbChId.Text = ch.ChannelId.ToString();
|
tbChCap.Text = ch.Capability;
|
tbChVolt.Text = ch.MaxVoltage.ToString("F2");
|
tbChCurr.Text = ch.MaxCurrent.ToString("F2");
|
}
|
}
|
catch (Exception ex)
|
{
|
ToastHelper.Error($"加载通道数据失败: {ex.Message}");
|
}
|
}
|
|
private void DeleteChannel_Click(object sender, RoutedEventArgs e)
|
{
|
try
|
{
|
if (sender is Button btn && btn.Tag is DeviceChannel ch)
|
{
|
if (MsgBoxHelper.WarnMessage(this, $"确定要删除通道 {ch.ChannelId} 吗?") == MessageBoxResult.OK)
|
{
|
_channels.Remove(ch);
|
}
|
}
|
}
|
catch (Exception ex)
|
{
|
ToastHelper.Error($"删除通道失败: {ex.Message}");
|
}
|
}
|
|
private void SaveChannel_Click(object sender, RoutedEventArgs e)
|
{
|
try
|
{
|
if (!int.TryParse(tbChId.Text, out int chId) || chId < 0)
|
{
|
ToastHelper.Warning("请输入有效的通道编号");
|
return;
|
}
|
|
double.TryParse(tbChVolt.Text, out double volt);
|
double.TryParse(tbChCurr.Text, out double curr);
|
|
var existing = _channels.FirstOrDefault(c => c.ChannelId == chId);
|
if (existing != null)
|
{
|
existing.Capability = tbChCap.Text ?? string.Empty;
|
existing.MaxVoltage = volt;
|
existing.MaxCurrent = curr;
|
}
|
else
|
{
|
_channels.Add(new DeviceChannel
|
{
|
DeviceId = _device.DeviceId ?? tbDeviceId.Text,
|
ChannelId = chId,
|
Capability = tbChCap.Text ?? string.Empty,
|
MaxVoltage = volt,
|
MaxCurrent = curr,
|
});
|
}
|
ClearChannelInputs();
|
ToastHelper.Success("通道已保存");
|
}
|
catch (Exception ex)
|
{
|
ToastHelper.Error($"保存通道失败: {ex.Message}");
|
}
|
}
|
|
private void DelChannel_Click(object sender, RoutedEventArgs e)
|
{
|
try
|
{
|
var selected = channelListView.SelectedItem as DeviceChannel;
|
if (selected == null)
|
{
|
ToastHelper.Warning("请先选中要删除的通道");
|
return;
|
}
|
if (MsgBoxHelper.WarnMessage(this, $"确定要删除通道 {selected.ChannelId} 吗?") == MessageBoxResult.OK)
|
{
|
_channels.Remove(selected);
|
}
|
}
|
catch (Exception ex)
|
{
|
ToastHelper.Error($"删除通道失败: {ex.Message}");
|
}
|
}
|
|
private void ClearChannelInputs()
|
{
|
tbChId.Text = string.Empty;
|
tbChCap.Text = string.Empty;
|
tbChVolt.Text = string.Empty;
|
tbChCurr.Text = string.Empty;
|
}
|
|
#endregion
|
|
#region 保存/取消
|
|
private void SaveBtn_Click(object sender, RoutedEventArgs e)
|
{
|
try
|
{
|
// 验证
|
var deviceId = tbDeviceId.Text?.Trim();
|
if (string.IsNullOrEmpty(deviceId))
|
{
|
ToastHelper.Warning("设备ID不能为空");
|
return;
|
}
|
|
if (cbKind.SelectedItem is not DeviceKind kind)
|
{
|
ToastHelper.Warning("请选择设备类型");
|
return;
|
}
|
|
if (cbTransport.SelectedItem is not TransportType transport)
|
{
|
ToastHelper.Warning("请选择传输方式");
|
return;
|
}
|
|
var endpoint = tbEndpoint.Text?.Trim();
|
if (string.IsNullOrEmpty(endpoint))
|
{
|
ToastHelper.Warning("连接端点不能为空");
|
return;
|
}
|
|
// 验证 Endpoint 格式
|
if (transport == TransportType.Tcp)
|
{
|
if (!endpoint.Contains(":") && !endpoint.Contains("."))
|
{
|
ToastHelper.Warning("TCP端点格式不正确,应为 IP:Port 格式");
|
return;
|
}
|
}
|
else if (transport == TransportType.Can)
|
{
|
// CAN 端点格式:总线名称:节点编号 如 "CAN_BUS_1:0"
|
var parts = endpoint.Split(':');
|
if (parts.Length != 2 || string.IsNullOrWhiteSpace(parts[0]) || !int.TryParse(parts[1], out int nodeIdx) || nodeIdx < 0)
|
{
|
ToastHelper.Warning("CAN端点格式不正确,应为 总线名称:节点编号(如 CAN_BUS_1:0)");
|
return;
|
}
|
}
|
|
// 检查 DeviceId 是否重复(新增时)
|
if (_isNew)
|
{
|
var existing = _model.GetDeviceById(deviceId);
|
if (existing != null)
|
{
|
ToastHelper.Warning($"设备ID [{deviceId}] 已存在");
|
return;
|
}
|
}
|
|
// 保存设备
|
_device.DeviceId = deviceId;
|
_device.Kind = kind;
|
_device.DriverType = tbDriverType.Text?.Trim() ?? string.Empty;
|
_device.Transport = transport;
|
_device.Endpoint = endpoint;
|
|
_model.SaveDevice(_device);
|
|
// 保存通道
|
foreach (var ch in _channels)
|
{
|
ch.DeviceId = deviceId;
|
_model.SaveChannel(ch);
|
}
|
|
DialogResult = true;
|
Close();
|
}
|
catch (Exception ex)
|
{
|
ToastHelper.Error($"保存失败: {ex.Message}");
|
}
|
}
|
|
private void CancelBtn_Click(object sender, RoutedEventArgs e)
|
{
|
DialogResult = false;
|
Close();
|
}
|
|
private void CbTransport_SelectionChanged(object sender, SelectionChangedEventArgs e)
|
{
|
UpdateEndpointHint();
|
}
|
|
/// <summary>
|
/// 根据传输方式更新端点输入框提示
|
/// </summary>
|
private void UpdateEndpointHint()
|
{
|
if (cbTransport.SelectedItem is TransportType tt)
|
{
|
switch (tt)
|
{
|
case TransportType.Can:
|
Panuon.WPF.UI.TextBoxHelper.SetWatermark(tbEndpoint, "CAN总线端点,格式: 总线名称:节点编号(如 CAN_BUS_1:0)");
|
break;
|
case TransportType.Serial:
|
Panuon.WPF.UI.TextBoxHelper.SetWatermark(tbEndpoint, "串口号,如 COM3:115200:8:N:1");
|
break;
|
case TransportType.Visa:
|
Panuon.WPF.UI.TextBoxHelper.SetWatermark(tbEndpoint, "VISG 地址,如 TCPIP0::192.168.1.100::inst0::INSTR");
|
break;
|
case TransportType.SDK:
|
Panuon.WPF.UI.TextBoxHelper.SetWatermark(tbEndpoint, "SDK 设备标识,如 SDK://DeviceName/Instance");
|
break;
|
default:
|
Panuon.WPF.UI.TextBoxHelper.SetWatermark(tbEndpoint, "例: 192.168.10.124:30000 或 COM3");
|
break;
|
}
|
}
|
}
|
|
/// <summary>
|
/// 根据设备类型建议默认驱动类型
|
/// </summary>
|
private void UpdateDriverHint()
|
{
|
// 保留现有驱动类型,不自动修改。仅当为空时提示默认值
|
if (string.IsNullOrWhiteSpace(tbDriverType.Text) && cbKind.SelectedItem is DeviceKind kind)
|
{
|
string hint = kind switch
|
{
|
DeviceKind.CanDevice => "CAN",
|
DeviceKind.PowerSupply => "SCPI",
|
DeviceKind.PlcDevice => "S7",
|
DeviceKind.Chamber => "Tcp",
|
DeviceKind.DAQ => "Tcp",
|
_ => ""
|
};
|
if (!string.IsNullOrEmpty(hint))
|
{
|
tbDriverType.Text = hint;
|
}
|
}
|
}
|
|
#endregion
|
}
|
}
|