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; [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; 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)); } 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); }; } 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) { var LoginResponse = JsonSerializer.Deserialize(msg); if (Type.type == "login_1") { if (LoginResponse!.status == "success" && LoginResponse != null) { token = LoginResponse.token; 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(); } }); log.Info($"用户 {UserName} 登录成功(token:{token})"); } 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 == "login_0" && LoginResponse != null) { log.Warn($"登录失败: {LoginResponse.message}\nMsg:{msg}"); Application.Current.Dispatcher.Invoke(() => { var loginWindow = Application.Current.Windows.OfType().FirstOrDefault(); if (loginWindow != null) { loginWindow.LoginMsg = "用户名或密码错误"; } }); } else if (Type.type == "chat") { var chat = JsonSerializer.Deserialize(msg); if (chat != null) { Application.Current.Dispatcher.Invoke(() => { // 处理聊天消息 if (chat.user == UserName) { var chatmessage = new ChatMessage { Sender = chat.user ?? "未知用户", Type = MessageType.Text, Image = new BitmapImage(new Uri(chat.image ?? "pack://application:,,,/resource/user.png", UriKind.Absolute)), Content = chat.message ?? "(无内容)", 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 ?? "未知用户", Type = MessageType.Text, Image = new BitmapImage(new Uri(chat.image ?? "pack://application:,,,/resource/user.png", UriKind.Absolute)), Content = chat.message ?? "(无内容)", Timestamp = chat.timestamp, Alignment = HorizontalAlignment.Left, SenderColor = new SolidColorBrush(Colors.Black) }; var mainWindow = Application.Current.Windows.OfType().FirstOrDefault(); mainWindow?.Messages.Add(chatmessage); } }); } else { log.Error("反序列化聊天数据时返回了 null"); } } 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 }; 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)); } } } }