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();
}
}
}
}
}