ChatX/chatclient/MainWindow.xaml.cs
XuShanQiXun f4de02ec38 优化消息处理与界面翻译
在 `ChatDataModel.cs` 中添加了控件引用并重命名消息类型属性。
在 `TrayIconManager.cs` 中将菜单项文本翻译为中文并注释掉部分代码。
调整 `LoginWindow.xaml` 的窗口尺寸。
在 `MainWindow.xaml` 中添加了 `x:Name` 属性和数据触发器,改善了用户体验。
在 `MainWindow.xaml.cs` 中添加了用户登录时的欢迎消息逻辑,并统一了消息类型属性名称。
2025-06-07 18:37:25 +08:00

356 lines
15 KiB
C#

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
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
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<ChatMessage> Messages { get; } = new ObservableCollection<ChatMessage>();
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<RegisterData>(msg);
if (Type != null)
{
var LoginResponse = JsonSerializer.Deserialize<LoginResultData>(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<MainWindow>().FirstOrDefault();
if (mainWindow != null)
{
mainWindow.Username = UserName;
mainWindow.Show();
var loginWindow = Application.Current.Windows.OfType<LoginWindow>().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} !",
Timestamp = DateTime.Now,
Alignment = HorizontalAlignment.Center,
SenderColor = new SolidColorBrush(Colors.Gray)
};
mainWindow?.Messages.Add(chatmessage);
}
});
log.Info($"用户 {UserName} 登录成功(token:{token})");
}
else
{
Application.Current.Dispatcher.Invoke(() =>
{
var loginWindow = Application.Current.Windows.OfType<LoginWindow>().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<LoginWindow>().FirstOrDefault();
if (loginWindow != null)
{
loginWindow.LoginMsg = "用户名或密码错误";
}
});
}
else if (Type.type == "chat")
{
var chat = JsonSerializer.Deserialize<ChatRegisterData>(msg);
if (chat != null)
{
Application.Current.Dispatcher.Invoke(() =>
{
// 处理聊天消息
if (chat.user == UserName)
{
var chatmessage = new ChatMessage
{
Sender = chat.user ?? "未知用户",
MsgType = 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<MainWindow>().FirstOrDefault();
mainWindow?.Messages.Add(chatmessage);
}
else
{
var chatmessage = new ChatMessage
{
Sender = chat.user ?? "未知用户",
MsgType = 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<MainWindow>().FirstOrDefault();
mainWindow?.Messages.Add(chatmessage);
}
});
}
else
{
log.Error("反序列化聊天数据时返回了 null");
}
}
else
{
log.Error($"未知的消息类型: {Type.type},请检查服务器响应格式");
Application.Current.Dispatcher.Invoke(() =>
{
var loginWindow = Application.Current.Windows.OfType<LoginWindow>().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<MainWindow>().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)
{
// 清理资源
Client?.Shutdown(SocketShutdown.Both);
Client?.Close();
Client?.Dispose();
token = null;
_trayManager?.Dispose();
}
}
}