using System; using System.Collections.Specialized; using System.Linq; using System.Windows; using System.Windows.Controls; using System.Windows.Media; using TeamAAS.Communication.Base; using TeamAAS.Communication.Interfaces; namespace TeamAAS.Communication.UI { /// /// 默认通讯调试页:按设备类型自适应——PLC 设备(PlcCommunicationBase)显示寄存器读写(带数据类型/长度), /// 其余(串口/文本)显示收发;底部收发/读写日志(双击清空)。 /// 未在 [Communication] 特性指定 DebugPageType 的设备均用本页。直接操作 BindCommunication 得到的实例。 /// public partial class DefaultCommunicationDebugPage : UserControl, ICommunicationDebugPage { private ICommunication _comm; private BindableCommunicationBase _logDevice; public DefaultCommunicationDebugPage() { InitializeComponent(); TypeCombo.ItemsSource = Enum.GetValues(typeof(DebugDataType)); TypeCombo.SelectedItem = DebugDataType.Int; IsEnabled = false; } public void BindCommunication(ICommunication communication) { UnbindCommunication(); _comm = communication; bool isPlc = communication is PlcCommunicationBase; PlcPanel.Visibility = isPlc ? Visibility.Visible : Visibility.Collapsed; TextPanel.Visibility = isPlc ? Visibility.Collapsed : Visibility.Visible; _logDevice = communication as BindableCommunicationBase; LogList.ItemsSource = _logDevice == null ? null : _logDevice.DebugLog; if (_logDevice != null) _logDevice.DebugLog.CollectionChanged += OnLogChanged; IsEnabled = communication != null; ScrollLast(); } public void UnbindCommunication() { if (_logDevice != null) _logDevice.DebugLog.CollectionChanged -= OnLogChanged; _logDevice = null; _comm = null; LogList.ItemsSource = null; IsEnabled = false; } private void OnLogChanged(object sender, NotifyCollectionChangedEventArgs e) { if (e.Action == NotifyCollectionChangedAction.Add) Dispatcher.BeginInvoke(new Action(ScrollLast), System.Windows.Threading.DispatcherPriority.Normal); } private void ScrollLast() { if (LogList.Items.Count == 0) return; var last = LogList.Items[LogList.Items.Count - 1]; LogList.ScrollIntoView(last); var sv = FindScrollViewer(LogList); if (sv != null) sv.ScrollToEnd(); } private static ScrollViewer FindScrollViewer(DependencyObject root) { if (root == null) return null; for (int i = 0; i < VisualTreeHelper.GetChildrenCount(root); i++) { var child = VisualTreeHelper.GetChild(root, i); if (child is ScrollViewer) return (ScrollViewer)child; var found = FindScrollViewer(child); if (found != null) return found; } return null; } private void LogList_MouseDoubleClick(object sender, System.Windows.Input.MouseButtonEventArgs e) { if (_logDevice != null) _logDevice.DebugLog.Clear(); } private void BtnSend_Click(object sender, RoutedEventArgs e) { if (_comm == null || string.IsNullOrEmpty(TxtSend.Text)) return; try { _comm.WriteValue(null, TxtSend.Text); if (_logDevice != null) _logDevice.AppendLog("TX: " + TxtSend.Text); } catch (Exception ex) { if (_logDevice != null) _logDevice.AppendLog("发送失败: " + ex.Message); } } private void BtnRead_Click(object sender, RoutedEventArgs e) { var plc = _comm as PlcCommunicationBase; if (plc == null) return; try { string addr = (TxtAddress.Text ?? "").Trim(); DebugDataType type = CurrentType; ushort len = CurrentLength; var result = plc.ReadValue(addr, type, len); string lenStr = len > 1 ? (", len=" + len) : ""; plc.AppendLog("读取 " + addr + " (" + type + lenStr + ") => " + FormatResult(result)); } catch (Exception ex) { plc.AppendLog("读取失败: " + ex.Message); } } private void BtnWrite_Click(object sender, RoutedEventArgs e) { var plc = _comm as PlcCommunicationBase; if (plc == null) return; try { string addr = (TxtAddress.Text ?? "").Trim(); DebugDataType type = CurrentType; ushort len = CurrentLength; object val = ParseDebugValue(TxtWriteValue.Text, type); Array arr = val as Array; if (arr != null && arr.Length != len) { plc.AppendLog("写入失败: 数组长度(" + arr.Length + ")与长度设置(" + len + ")不一致"); return; } if (arr != null) plc.WriteValue(addr, val, type, len); else plc.WriteValue(addr, val, type); string lenStr = arr != null ? (", len=" + len) : ""; plc.AppendLog("写入 " + addr + " (" + type + lenStr + ") = " + FormatResult(val)); } catch (Exception ex) { plc.AppendLog("写入失败: " + ex.Message); } } private DebugDataType CurrentType { get { if (TypeCombo.SelectedItem is DebugDataType) return (DebugDataType)TypeCombo.SelectedItem; return DebugDataType.Int; } } private ushort CurrentLength { get { int n; if (!int.TryParse((TxtLength.Text ?? "").Trim(), out n)) n = 1; if (n < 1) n = 1; if (n > 100) n = 100; return (ushort)n; } } private static string FormatResult(object value) { if (value == null) return "(null)"; Array arr = value as Array; if (arr != null) return "[" + string.Join(",", arr.Cast()) + "]"; return value.ToString(); } private static object ParseDebugValue(string text, DebugDataType type) { if (!string.IsNullOrWhiteSpace(text)) { string t = text.Trim(); if (t.StartsWith("[") && t.EndsWith("]")) { string inner = t.Substring(1, t.Length - 2); var vals = inner.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries) .Select(p => p.Trim()).Where(p => p.Length > 0).ToArray(); if (vals.Length > 0) { switch (type) { case DebugDataType.Bool: return vals.Select(p => bool.Parse(p)).ToArray(); case DebugDataType.Byte: return vals.Select(p => byte.Parse(p)).ToArray(); case DebugDataType.Short: return vals.Select(p => short.Parse(p)).ToArray(); case DebugDataType.Ushort: return vals.Select(p => ushort.Parse(p)).ToArray(); case DebugDataType.Int: return vals.Select(p => int.Parse(p)).ToArray(); case DebugDataType.Uint: return vals.Select(p => uint.Parse(p)).ToArray(); case DebugDataType.Long: return vals.Select(p => long.Parse(p)).ToArray(); case DebugDataType.Ulong: return vals.Select(p => ulong.Parse(p)).ToArray(); case DebugDataType.Float: return vals.Select(p => float.Parse(p)).ToArray(); case DebugDataType.Double: return vals.Select(p => double.Parse(p)).ToArray(); } } } } switch (type) { case DebugDataType.Bool: return bool.Parse(text); case DebugDataType.Byte: return byte.Parse(text); case DebugDataType.Short: return short.Parse(text); case DebugDataType.Ushort: return ushort.Parse(text); case DebugDataType.Int: return int.Parse(text); case DebugDataType.Uint: return uint.Parse(text); case DebugDataType.Long: return long.Parse(text); case DebugDataType.Ulong: return ulong.Parse(text); case DebugDataType.Float: return float.Parse(text); case DebugDataType.Double: return double.Parse(text); default: return text; } } } }