基于MVVM与Autofac实现登录后窗口间用户数据传递问题
问题背景
我正在开发首个正式MVVM应用,登录是用户操作的第一步,MainWindow的Frame中承载着登录页面。希望用户输入用户名和密码后,打开新窗口并展示用户ID与名称。当前已使用MainViewModel、UserAccountViewModel及Autofac进行依赖注入,相关代码如下:
MainViewModel 核心代码
public IEventAggregator _eventaggregator; private Func<IUserAccountViewModel> _useraccountviewmodelCreator; private IUserAccountViewModel _useraccountViewModel; public MainViewModel(INavigationViewModel navigationveiwmodel , Func<IUserAccountViewModel> useraccountviewmodelCreator,IEventAggregator EventAggregator) { _useraccountviewmodelCreator = useraccountviewmodelCreator; _eventaggregator = EventAggregator; _eventaggregator.GetEvent<OpenDetailViewEvent>().Subscribe(OnOpenDetailView); _eventaggregator.GetEvent<AfterUserSavedEvent>().Subscribe(AfterUserSaved); NavigationViewModel = navigationveiwmodel; CreateNewUserCommand = new DelegateCommand(OnCreateNewUserExecute); LogInCommand = new DelegateCommand(onLoginExecute); _eventaggregator.GetEvent<OpenDetailViewEvent>().Subscribe(AfterLoginExecute); } private async void onLoginExecute() { UserAccountViewModel = _useraccountviewmodelCreator(); await UserAccountViewModel.LoadAsyncByPassword(UserName, HashSomeText(Password)); } private async void AfterLoginExecute(int? Userid) { UserAccountViewModel = _useraccountviewmodelCreator(); await UserAccountViewModel.LoadAsync(Userid); CheckID = Userid.Value; } public INavigationViewModel NavigationViewModel { get; set; } public ICommand CreateNewUserCommand { get; set; } public ICommand LogInCommand { get; set; } public IUserAccountViewModel UserAccountViewModel { get { return _useraccountViewModel; } set { _useraccountViewModel = value; OnPropertyChanged(); } }
UserAccountViewModel 核心代码
public async Task LoadAsyncByPassword(string UserName, string password) { var user = await _userRepository.GetAsyncByPassword(UserName, password); if(user!=null) { _eventaggregator.GetEvent<OpenDetailViewEvent>().Publish(user.Id); } }
Bootstrapper 注册代码
var bulider = new ContainerBuilder(); bulider.RegisterType<EventAggregator>().As<IEventAggregator>().SingleInstance(); bulider.RegisterType<BudGDbContext>().AsSelf(); bulider.RegisterType<SplashScreen>().AsSelf(); bulider.RegisterType<AuthorisationsWindow>().AsSelf(); bulider.RegisterType<MainWindow>().AsSelf(); bulider.RegisterType<MainViewModel>().AsSelf(); bulider.RegisterType<UserAccountViewModel>().As<IUserAccountViewModel>(); bulider.RegisterType<NavigationViewModel>().As<INavigationViewModel>(); bulider.RegisterType<LookupDataSeervice>().AsImplementedInterfaces(); bulider.RegisterType<UserRepository>().As<IUserRepository>(); return bulider.Build();
当前问题:登录后能获取到用户ID与名称,但切换至MainWindow后ID重置为0,请问如何从AuthorisationsWindow跳转至MainWindow并保留用户ID与名称?
解决方案
核心问题分析
你的问题根源在于窗口跳转时ViewModel实例是相互独立的,当前通过EventAggregator传递用户ID的方式只能在事件订阅时临时获取,但新打开的MainWindow对应的MainViewModel初始化时没有持久化这个状态,导致后续ID丢失。解决思路是引入一个全局的用户状态存储服务,让所有ViewModel能共享登录用户的信息。
1. 创建全局用户状态服务
首先定义一个单例服务来存储当前登录用户的信息,确保整个应用中只有一个实例:
public interface ICurrentUserService { int? CurrentUserId { get; set; } string CurrentUserName { get; set; } // 可根据需求扩展更多用户属性,比如邮箱、角色等 } public class CurrentUserService : ICurrentUserService { public int? CurrentUserId { get; set; } public string CurrentUserName { get; set; } }
然后在Bootstrapper中将其注册为单例:
// 添加这行代码到ContainerBuilder注册中 builder.RegisterType<CurrentUserService>().As<ICurrentUserService>().SingleInstance();
2. 修改登录逻辑,持久化用户信息到全局服务
在UserAccountViewModel中注入ICurrentUserService,登录成功后将用户信息存入该服务:
// 先注入服务 private readonly ICurrentUserService _currentUserService; public UserAccountViewModel(IUserRepository userRepository, IEventAggregator eventAggregator, ICurrentUserService currentUserService) { _userRepository = userRepository; _eventaggregator = eventAggregator; _currentUserService = currentUserService; } public async Task LoadAsyncByPassword(string UserName, string password) { var user = await _userRepository.GetAsyncByPassword(UserName, password); if(user!=null) { // 把用户信息存入全局服务 _currentUserService.CurrentUserId = user.Id; _currentUserService.CurrentUserName = user.Name; _eventaggregator.GetEvent<OpenDetailViewEvent>().Publish(user.Id); } }
3. 让MainViewModel初始化时读取全局用户状态
修改MainViewModel的构造函数,注入ICurrentUserService,并在初始化时直接读取已存储的用户信息:
private readonly ICurrentUserService _currentUserService; public MainViewModel(INavigationViewModel navigationveiwmodel, Func<IUserAccountViewModel> useraccountviewmodelCreator, IEventAggregator EventAggregator, ICurrentUserService currentUserService) { _useraccountviewmodelCreator = useraccountviewmodelCreator; _eventaggregator = EventAggregator; _currentUserService = currentUserService; _eventaggregator.GetEvent<OpenDetailViewEvent>().Subscribe(OnOpenDetailView); _eventaggregator.GetEvent<AfterUserSavedEvent>().Subscribe(AfterUserSaved); NavigationViewModel = navigationveiwmodel; CreateNewUserCommand = new DelegateCommand(OnCreateNewUserExecute); LogInCommand = new DelegateCommand(onLoginExecute); _eventaggregator.GetEvent<OpenDetailViewEvent>().Subscribe(AfterLoginExecute); // 初始化时直接读取全局服务中的用户ID if (_currentUserService.CurrentUserId.HasValue) { CheckID = _currentUserService.CurrentUserId.Value; // 可以直接加载用户信息,无需等待事件 await AfterLoginExecute(_currentUserService.CurrentUserId); } }
4. 优化窗口跳转的生命周期
确保登录成功后,关闭登录窗口(AuthorisationsWindow)并打开MainWindow时,MainWindow能正确获取全局状态。可以在AfterLoginExecute方法中添加窗口切换逻辑:
private async void AfterLoginExecute(int? Userid) { UserAccountViewModel = _useraccountviewmodelCreator(); await UserAccountViewModel.LoadAsync(Userid); CheckID = Userid.Value; // 关闭登录窗口,打开MainWindow var mainWindow = App.Container.Resolve<MainWindow>(); mainWindow.Show(); // 找到并关闭当前的登录窗口 var loginWindow = Application.Current.Windows.OfType<AuthorisationsWindow>().FirstOrDefault(); loginWindow?.Close(); }
注意:这里假设你在App类中保留了Autofac容器的引用(比如
public static IContainer Container { get; set; }),这样可以直接解析MainWindow实例。
5. 验证ViewModel注册方式
确保MainViewModel是每个MainWindow实例对应一个ViewModel(默认的AsSelf()注册方式是正确的),不要将其注册为单例,否则会导致多窗口状态冲突。全局状态只通过ICurrentUserService这个单例来维护即可。
总结
通过引入全局单例的用户状态服务,我们将登录用户的信息持久化到一个全局可访问的位置,这样无论跳转到哪个窗口,对应的ViewModel都能读取到正确的用户信息,避免了ID重置的问题。这种方式也符合MVVM的解耦原则,把状态管理从ViewModel中分离出来,让代码更易于维护和扩展。
内容的提问来源于stack exchange,提问作者Mahmoud Samy

