using System.Text; using System.Windows; using System.Windows.Controls; using System.Windows.Documents; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Imaging; using System.Windows.Navigation; using System.Windows.Shapes; using System.Net.Sockets;//socket库 using System.Net.Http; using System.Net; using System.IO; using System; using System.Security.Policy; using log4net; using log4net.Config; using System.Text.Json; using chatclient.Data; using System.ComponentModel; using System.Collections.ObjectModel; using System.Windows.Threading; using System.Collections.Specialized; using Hardcodet.Wpf.TaskbarNotification; [assembly: XmlConfigurator(ConfigFile = "config/log4net.config", Watch = true)] namespace chatclient { /// /// Interaction logic for MainWindow.xaml /// public partial class MainWindow : Window, INotifyPropertyChanged { LoginWindow Login = new(); static string? receive; public static string UserName { get; set; } = "?"; public static string? token = null; public static string? UserId = null; private static readonly ILog log = LogManager.GetLogger(typeof(MainWindow)); public static Socket? Client; public static readonly HttpClient HttpClient = new HttpClient(); public event PropertyChangedEventHandler? PropertyChanged; private string? _Username; public string? Username { get { return _Username; } set { _Username = value; Update("Username"); } } // 消息列表 public ObservableCollection Messages { get; } = new ObservableCollection(); private ItemsControl MessageList => messageList; private ScrollViewer MessageScroller => messageScroller; private void Update(string UpdateName) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(UpdateName)); } private TrayIconManager? _trayManager; public MainWindow() { InitializeComponent(); this.DataContext = this; log.Info("Hello World!"); this.Hide(); Client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); try { log.Info($"连接服务器 {Server.ServerIP}:{Server.ServerPort} "); Client.Connect(Server.ServerIP, Server.ServerPort); } catch (Exception ex) { Client.Close(); log.Error(ex); } Login.Show(); if(Client != null && Client.Connected == true) StartReceive(); MessageList.ItemsSource = Messages; ((INotifyCollectionChanged)MessageList.Items).CollectionChanged += (s, e) => { // 确保有足够的时间让UI更新 Dispatcher.BeginInvoke(new Action(() => { MessageScroller.ScrollToEnd(); }), DispatcherPriority.ContextIdle); }; //Loaded += MainWindow_Loaded; //Closed += MainWindow_Closed; } public static void StartReceive() { if (Client != null && Client.Connected == true) { Thread th = new Thread(Receive); th.Start(); } else { log.Fatal("在Client为NULL或未连接服务器时被调用StartReceive()"); } } static void Receive() { byte[] buffer = new byte[1024]; try { while (true) { int num = Client!.Receive(buffer); if (num == 0) break; if (Client.Poll(100, SelectMode.SelectRead) && Client.Available == 0 || !Client.Connected) { log.Error("连接已断开"); break; } receive = Encoding.UTF8.GetString(buffer, 0, num); response(receive); } } catch (Exception ex) { log.Error(ex); } finally { Client?.Close(); } } static void response(string msg) { log.Info($"收到服务器消息: {msg}"); try { var Type = JsonSerializer.Deserialize(msg); if (Type != null) { if (Type.type == "login") { var LoginResponse = JsonSerializer.Deserialize(msg); if (LoginResponse!.status == "succeed" && LoginResponse != null) { //token = LoginResponse.token; UserId = LoginResponse.userid ?? "Unid"; UserName = LoginResponse.username ?? "Unnamed"; Application.Current.Dispatcher.Invoke(() => { var mainWindow = Application.Current.Windows.OfType().FirstOrDefault(); if (mainWindow != null) { mainWindow.Username = UserName; mainWindow.Show(); var loginWindow = Application.Current.Windows.OfType().FirstOrDefault(); loginWindow?.Close(); mainWindow.Activate(); var chatmessage = new ChatMessage { Sender = "System", MsgType = MessageType.System, Image = new BitmapImage(new Uri("pack://application:,,,/resource/user.png")), Content = $"你好 {UserName} (id: {UserId} )!", Timestamp = DateTime.Now, Alignment = HorizontalAlignment.Center, SenderColor = new SolidColorBrush(Colors.Gray) }; mainWindow?.Messages.Add(chatmessage); } }); log.Info($"用户 {UserName} 登录成功(token:{token},userid:{UserId})"); } else if (LoginResponse!.status == "error_0") { log.Warn($"登录失败: {LoginResponse!.message}\nMsg:{msg}"); Application.Current.Dispatcher.Invoke(() => { var loginWindow = Application.Current.Windows.OfType().FirstOrDefault(); if (loginWindow != null) { loginWindow.LoginMsg = "用户名或密码错误"; } }); } else if (LoginResponse!.status == "error_2") { log.Warn($"登录失败: {LoginResponse!.message}\nMsg:{msg}"); Application.Current.Dispatcher.Invoke(() => { var loginWindow = Application.Current.Windows.OfType().FirstOrDefault(); if (loginWindow != null) { loginWindow.LoginMsg = "用户名长度必须在2到20个字符之间"; } }); } else { Application.Current.Dispatcher.Invoke(() => { var loginWindow = Application.Current.Windows.OfType().FirstOrDefault(); if (loginWindow != null) { loginWindow.LoginMsg = LoginResponse != null ? LoginResponse.message : "服务器返回错误"; } }); } } else if (Type.type == "register") { var SignResponse = JsonSerializer.Deserialize(msg); if (SignResponse!.status == "success") { log.Warn($"注册成功\nMsg:{msg}"); Application.Current.Dispatcher.Invoke(async () => { //var loginWindow = Application.Current.Windows.OfType().FirstOrDefault(); await LoginWindow.Login(true, LoginWindow.SignName, LoginWindow.SignPassword1); }); } else if (SignResponse!.status == "error_1") { log.Warn($"注册失败: {SignResponse!.message}\nMsg:{msg}"); Application.Current.Dispatcher.Invoke(() => { var loginWindow = Application.Current.Windows.OfType().FirstOrDefault(); if (loginWindow != null) { loginWindow.SignMsg = "密码长度必须在4到20个字符之间"; } }); } else if (SignResponse!.status == "error_2") { log.Warn($"注册失败: {SignResponse!.message}\nMsg:{msg}"); Application.Current.Dispatcher.Invoke(() => { var loginWindow = Application.Current.Windows.OfType().FirstOrDefault(); if (loginWindow != null) { loginWindow.SignMsg = "用户名长度必须在2到20个字符之间"; } }); } else if (SignResponse!.status == "error_3") { log.Warn($"注册失败: {SignResponse!.message}\nMsg:{msg}"); { Application.Current.Dispatcher.Invoke(() => { var loginWindow = Application.Current.Windows.OfType().FirstOrDefault(); if (loginWindow != null) { loginWindow.SignMsg = "用户名已存在"; } }); } } else { log.Error($"注册失败: {SignResponse!.message}\nMsg:{msg}"); Application.Current.Dispatcher.Invoke(() => { var loginWindow = Application.Current.Windows.OfType().FirstOrDefault(); if (loginWindow != null) { loginWindow.SignMsg = SignResponse != null ? SignResponse.message : "服务器返回错误"; } }); } } else if (Type.type == "chat") { var chat = JsonSerializer.Deserialize(msg); if (chat != null) { Application.Current.Dispatcher.Invoke(() => { // 处理聊天消息 if (chat.userid == UserId) { var chatmessage = new ChatMessage { Sender = chat.user ?? "未知用户", MsgType = MessageType.Text, Image = new BitmapImage(new Uri(chat.avatar ?? "pack://application:,,,/resource/user.png")), Content = chat.message ?? "(无内容)", Timestamp = chat.timestamp ?? DateTime.Now, Alignment = HorizontalAlignment.Right, SenderColor = new SolidColorBrush(Colors.Blue) }; var mainWindow = Application.Current.Windows.OfType().FirstOrDefault(); mainWindow?.Messages.Add(chatmessage); } else { var chatmessage = new ChatMessage { Sender = chat.user ?? "未知用户", MsgType = MessageType.Text, Image = new BitmapImage(new Uri(chat.avatar ?? "pack://application:,,,/resource/user.png")), Content = chat.message ?? "(无内容)", Timestamp = chat.timestamp ?? DateTime.Now, Alignment = HorizontalAlignment.Left, SenderColor = new SolidColorBrush(Colors.Black) }; var mainWindow = Application.Current.Windows.OfType().FirstOrDefault(); mainWindow?.Messages.Add(chatmessage); } }); } else { log.Error("反序列化聊天数据时返回了 null"); } } else if (Type.type == "ping") { } else { log.Error($"未知的消息类型: {Type.type},请检查服务器响应格式"); Application.Current.Dispatcher.Invoke(() => { var loginWindow = Application.Current.Windows.OfType().FirstOrDefault(); if (loginWindow != null) loginWindow.LoginMsg = "服务器返回了错误的值"; }); } } } catch (JsonException ex) { log.Error("JSON解析错误", ex); } catch (Exception ex) { log.Error("处理响应时发生错误", ex); } } private async void SendMessage_Click(object sender, RoutedEventArgs e) { await SendMessage(); } private async Task SendMessage() { if (string.IsNullOrWhiteSpace(txtMessage.Text)) return; // 获取当前选中的联系人 //var contact = cmbContacts.SelectedItem as Contact; // 判断是否为群组,若是则收件人设为“所有人”,否则为联系人显示名 //string recipient = contact?.IsGroup == true ? "所有人" : contact?.DisplayName; // 弃用的方法 // 创建新消息 //var newMessage = new ChatMessage //{ // Sender = "我", // Type = MessageType.Text, // Image = new BitmapImage(new Uri("pack://application:,,,/resource/user.png", UriKind.Absolute)), // 默认头像 // Content = txtMessage.Text, // Timestamp = DateTime.Now, // Alignment = HorizontalAlignment.Right, // 自己发送的消息靠右 // SenderColor = new SolidColorBrush(Colors.Blue) //}; var newChatMessage = new ChatData { type = "chat", message = txtMessage.Text, msgtype = MessageType.Text, userid = UserId ?? "Unid", // 使用UserId作为发送者ID token = token // 添加当前token }; string ChatJsonData = JsonSerializer.Serialize(newChatMessage); byte[] dataBytes = Encoding.UTF8.GetBytes(ChatJsonData); log.Info($"向服务器聊天信息(长度:{dataBytes.Length})"); // 检查Socket是否可用 if (Client?.Connected == true) { Client.Send(dataBytes); Application.Current.Dispatcher.Invoke(() => { txtMessage.Clear(); }); return; } log.Info("未连接服务器,尝试异步连接"); // 异步连接操作 await Task.Run(() => { try { Client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); Client?.Connect(IPAddress.Parse(Server.ServerIP), Server.ServerPort); StartReceive(); Client?.Send(dataBytes); Application.Current.Dispatcher.Invoke(() => { txtMessage.Clear(); }); } catch (Exception ex) { log.Error($"连接失败: {ex.Message}"); Client?.Close(); Application.Current.Dispatcher.Invoke(() => { var mainWindow = Application.Current.Windows.OfType().FirstOrDefault(); if (mainWindow != null) { QueueMessage("连接失败,请检查网络设置或服务器状态。"); } }); } }); // 添加到消息列表 //Messages.Add(newMessage); } private void QueueMessage(string message) { if (SnackbarThree.MessageQueue is { } messageQueue) { //use the message queue to send a message. //the message queue can be called from any thread Task.Factory.StartNew(() => messageQueue.Enqueue(message)); } } private void MainWindow_Loaded(object sender, RoutedEventArgs e) { // 初始化托盘管理器 _trayManager = new TrayIconManager(this); } private void MainWindow_Closed(object sender, System.EventArgs e) { log.Info("MainWindow 关闭事件触发,清理资源"); // 清理资源 if (Client!.Connected) Client?.Shutdown(SocketShutdown.Both); Client?.Close(); log.Info("关闭Socket连接"); Client?.Dispose(); token = null; _trayManager?.Dispose(); log.Info("托盘图标管理器已释放资源"); log.Info("Bye!"); } } }