You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

WPF聊天应用:登录后在ListView显示所有在线用户的最优方案

解决WPF聊天应用在线用户列表显示问题的最优实现方案

核心问题分析

现有代码存在以下关键缺陷导致无法显示所有在线用户:

  1. 职责划分混乱:LoginVM同时承担登录逻辑与主窗口用户列表管理,违反MVVM单一职责原则
  2. 缺少初始用户同步:仅监听新用户连接事件,登录成功后未获取服务器当前全量在线用户列表
  3. 未处理用户下线场景:没有监听用户断开连接的事件,列表无法动态更新

最优实现步骤

1. 重构ViewModel职责分离

  • LoginVM:专注登录认证、服务器连接初始化,登录成功后将必要数据传递给MainViewModel
  • MainViewModel:负责维护在线用户集合、处理用户连接/断开事件

2. 修改LoginVM代码

调整登录流程,先获取全量在线用户再初始化主窗口:

public class LoginVM : viewModelBase
{
    private readonly User user;
    private Server _server;
  
    public ICommand CombinedCommand { get; }
    public ICommand CloseLoginWindowCommand { get; }
    
    public LoginVM()
    {
        user = new User();
        _server = new Server();
        
        CombinedCommand = new RelayCommand(o =>
        {
            // 先连接服务器并获取全量在线用户
            _server.ConnectToServer(UserName);
            var initialUsers = _server.GetOnlineUsers(); // 新增服务器方法:返回当前所有在线用户
            // 初始化主窗口ViewModel
            InitializeMainWindow(initialUsers);
            CloseLoginWindow();
        }, o => canExecuteCommands(o));
    }

    public string UserName
    {
        get => user.Name;
        set
        {
            user.Name = value;
            OnPropertyChanged(nameof(UserName));
        }
    }

    private void InitializeMainWindow(IEnumerable<User> initialUsers)
    {
        var mainVM = new MainViewModel(_server, initialUsers);
        MainWindow mainWindow = new MainWindow();
        mainWindow.DataContext = mainVM;
        mainWindow.Show();
    }
    
    private bool canExecuteCommands(object parameter)
    {
        return parameter is string userName && !string.IsNullOrEmpty(userName);
    }

    private void CloseLoginWindow()
    {
        Application.Current.Windows[0]?.Close();
    }
}

3. 实现MainViewModel

负责用户集合管理与事件监听:

public class MainViewModel : viewModelBase
{
    private readonly Server _server;
    private readonly SynchronizationContext _syncContext = SynchronizationContext.Current;
    public ObservableCollection<User> OnlineUsers { get; }

    public MainViewModel(Server server, IEnumerable<User> initialUsers)
    {
        _server = server;
        OnlineUsers = new ObservableCollection<User>(initialUsers);
        // 订阅用户连接/断开事件
        _server.connectedEvent += OnUserConnected;
        _server.disconnectedEvent += OnUserDisconnected;
    }

    private void OnUserConnected()
    {
        var newUser = new User { Name = _server._packetReader.ReadMessage() };
        // 线程安全更新UI集合
        _syncContext.Post(_ =>
        {
            if (!OnlineUsers.Contains(newUser))
            {
                OnlineUsers.Add(newUser);
            }
        }, null);
    }

    private void OnUserDisconnected()
    {
        var disconnectedUserName = _server._packetReader.ReadMessage();
        _syncContext.Post(_ =>
        {
            var userToRemove = OnlineUsers.FirstOrDefault(u => u.Name == disconnectedUserName);
            if (userToRemove != null)
            {
                OnlineUsers.Remove(userToRemove);
            }
        }, null);
    }

    // 清理事件订阅,避免内存泄漏
    ~MainViewModel()
    {
        _server.connectedEvent -= OnUserConnected;
        _server.disconnectedEvent -= OnUserDisconnected;
    }
}

4. 优化User类

实现相等性判断,确保集合操作准确:

public class User : IEquatable<User>
{
    public string Name { get; set; }

    public bool Equals(User other)
    {
        return other != null && string.Equals(Name, other.Name, StringComparison.OrdinalIgnoreCase);
    }

    public override bool Equals(object obj) => Equals(obj as User);
    public override int GetHashCode() => Name?.GetHashCode(StringComparison.OrdinalIgnoreCase) ?? 0;
}

5. 主窗口ListView绑定

在MainWindow.xaml中绑定OnlineUsers集合:

<ListView ItemsSource="{Binding OnlineUsers}" 
          DisplayMemberPath="Name"
          Margin="10"/>

关键优化点说明

  • 使用SynchronizationContext替代Dispatcher.Invoke,实现更通用的线程安全UI更新
  • 明确ViewModel职责边界,LoginVM只处理登录流程,MainVM专注用户列表管理
  • 补充用户下线事件处理,保证列表实时性
  • 实现User类的相等性接口,避免重复添加或错误删除用户

内容的提问来源于stack exchange,提问作者Dima Natchkebia

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.06 17:17:47