using CommunityToolkit.Mvvm.ComponentModel; using System.Collections.ObjectModel; using System.Globalization; using System.Text; using System.Text.RegularExpressions; using System.Windows; using System.Windows.Controls; using System.Windows.Data; using System.Windows.Documents; using System.Windows.Media; using TouchSocket.Core; using TouchSocket.Sockets; using UtilLib; namespace Plugin.UICollection { public enum DataType { String = 0, HEX = 1 } public enum SupportEncode { GBK = 0, ASCII = 1, UTF8 = 2 } public class EndMarkSource { public string Name { get; set; } public int Type { get; set; } } public class ByteStringConverter : IValueConverter { private TcpDebugger control { get; set; } public ByteStringConverter(TcpDebugger control) { this.control = control; } public static string GroupByTwo(string str) { if (string.IsNullOrEmpty(str)) return string.Empty; StringBuilder result = new StringBuilder(); for (int i = 0; i < str.Length; i += 2) { if (i > 0) result.Append(' '); int length = Math.Min(2, str.Length - i); result.Append(str.Substring(i, length)); } return result.ToString(); } public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { DataType sendType = control.SendDataType; if (sendType != DataType.HEX) { return value; } var str = value.ToString(); return GroupByTwo(str); } public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { DataType sendType = control.SendDataType; if (sendType != DataType.HEX) { return value; } return value.ToString().Replace(" ", ""); } } /// /// TcpDebugger.xaml 的交互逻辑 /// [ObservableObject] public partial class TcpDebugger : UserControl { [ObservableProperty] private string ip = "127.0.0.1"; [ObservableProperty] private int port; [ObservableProperty] private int clientPort; [ObservableProperty] private DataType receiveDataType = DataType.String; [ObservableProperty] private DataType sendDataType = DataType.String; [ObservableProperty] private bool isConnected = false; [ObservableProperty] private string sendText; [ObservableProperty] private SupportEncode receiveEncode; [ObservableProperty] private SupportEncode sendEncode; [ObservableProperty] private ObservableCollection endMarkSource = new ObservableCollection { new EndMarkSource{ Name="无",Type=-1}, new EndMarkSource{ Name="\\r",Type=0}, new EndMarkSource{ Name="\\r\\n",Type=1}, new EndMarkSource{ Name="自定义",Type=2}, }; [ObservableProperty] private int endMark; [ObservableProperty] private string customEndMark; private ByteStringConverter bsConverter; private TcpClient client; public TcpDebugger() { DataContext = this; InitializeComponent(); sendEncodeInput.ItemsSource = Enum.GetValues(typeof(SupportEncode)).Cast(); receiveEncodeInput.ItemsSource = Enum.GetValues(typeof(SupportEncode)).Cast(); DataObject.AddPastingHandler(sendBox, OnPasting); bsConverter = new ByteStringConverter(this); BindingOperations.SetBinding(sendBox, TextBox.TextProperty, new Binding(nameof(SendText)) { Source = this, Mode = BindingMode.TwoWay, UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged, Converter = bsConverter }); } private void Button_Click(object sender, RoutedEventArgs e) { var btn = (Button)sender; if (btn.Tag.ToString() == "Connect") { TryConnect(); return; } if (btn.Tag.ToString() == "Send") { TrySend(); return; } } private void TryConnect() { try { if (IsConnected) return; var config = new TouchSocketConfig().SetRemoteIPHost($"tcp://{Ip}:{Port}"); client = new TcpClient(); client.Received = TcpReceived; client.Connected = (sender, e) => { Dispatcher.Invoke(() => { Add("连接", "连接成功", Brushes.Green); IsConnected = true; }); return EasyTask.CompletedTask; }; client.Closed = (sender, e) => { Dispatcher.Invoke(() => { Add("连接", "连接断开", Brushes.Red); IsConnected = false; }); return EasyTask.CompletedTask; }; client.SetupAsync(config); client.ConnectAsync(); } catch (Exception ex) { IsConnected = false; // throw ex; } } private Task TcpReceived(object sender, ReceivedDataEventArgs e) { try { var datas = e.Memory.Span.ToArray(); string msg = null; if (ReceiveDataType == DataType.HEX) { msg = HexUtil.ByteArrayToHex(datas); } else { if (ReceiveEncode == SupportEncode.GBK) { msg = Encoding.Default.GetString(datas); } else if (ReceiveEncode == SupportEncode.ASCII) { msg = Encoding.ASCII.GetString(datas); } else { msg = Encoding.UTF8.GetString(datas); } } Add("接收", msg, Brushes.Green); } catch (Exception ex) { //log.Error($"TcpReceived Error.", ex); } return EasyTask.CompletedTask; } private byte[] GetBytes(out string msg) { msg = null; if (string.IsNullOrEmpty(SendText)) { return null; } if (SendDataType == DataType.String) { msg = SendText + GetEndMark(); if (SendEncode == SupportEncode.GBK) { return Encoding.Default.GetBytes(msg); } if (SendEncode == SupportEncode.ASCII) { return Encoding.ASCII.GetBytes(msg); } if (SendEncode == SupportEncode.UTF8) { return Encoding.UTF8.GetBytes(msg); } return null; } msg = SendText; if (msg.Length % 2 != 0) { msg = msg.Insert(msg.Length - 1, "0"); } msg = ByteStringConverter.GroupByTwo(msg); return HexUtil.HexToByteArray(msg); } private string GetEndMark() { if (EndMark == -1) { return string.Empty; } if (EndMark == 0) { return "\r"; } if (EndMark == 1) { return "\r\n"; } if (EndMark == 2) { return CustomEndMark; } return string.Empty; } public void TrySend() { if (!IsConnected) { MessageBox.Show("请先连接", "提示"); return; } var datas = GetBytes(out string msg); if (datas != null) { client.SendAsync(datas).Wait(); Add("发送", msg, Brushes.Blue); // SendText = string.Empty; } } public void Add(string type, string text, Brush color) { Dispatcher.BeginInvoke(() => { string time = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"); Run run = new Run(); run.Text = $"{time} {type}\r\n"; run.Foreground = Brushes.Gray; Paragraph paragraph = new Paragraph(run) { LineHeight = 1 }; run = new Run(); run.Text = $"{text}\r\n"; run.Foreground = color; paragraph.Inlines.Add(run); //也可以插入到最后面 console.Document.Blocks.InsertAfter(console.Document.Blocks.LastBlock, paragraph); //插入到最前面 //rtxtLog.Document.Blocks.Add(paragraph); // 滚动至最后行 //rtxtLog.ScrollToEnd(); //Console.ScrollToHome(); console.ScrollToEnd(); // 删除 //if (Console.Document.Blocks.Count > 10000) //{ // for (int i = 1000; i < Console.Document.Blocks.Count; i++) // { // _ = Console.Document.Blocks.Remove(Console.Document.Blocks.FirstBlock); // } //} }, System.Windows.Threading.DispatcherPriority.Normal); } private static readonly Regex HexRegex = new Regex("^[0-9A-Fa-f]+$"); private void TextBox_PreviewTextInput(object sender, System.Windows.Input.TextCompositionEventArgs e) { if (SendDataType != DataType.HEX) { return; } var tb = (TextBox)sender; string segment = e.Text; if (!HexRegex.IsMatch(segment)) { tb.Text = tb.Text.Replace(segment, ""); tb.CaretIndex = tb.Text.Length; e.Handled = true; return; } // tb.Text = tb.Text.ToUpper(); base.OnPreviewTextInput(e); } private void OnPasting(object sender, DataObjectPastingEventArgs e) { if (SendDataType != DataType.HEX) { return; } if (e.DataObject.GetDataPresent(typeof(string))) { string text = (string)e.DataObject.GetData(typeof(string)); text = text.Replace(" ", ""); if (!HexRegex.IsMatch(text)) { e.CancelCommand(); } } } } }