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

如何在Prism框架中正确实现模块间事件消息传递?WPF MVVM场景

你的这个思路完全站得住脚,Prism的事件聚合器就是为这种解耦的跨组件通信场景设计的!我帮你把整个实现流程理清楚,一步步来:

实现WPF Prism登录后跳转主页的完整方案

1. 定义登录成功事件

首先确保你的UserLoggedInEvent继承自Prism的PubSubEvent,并携带用户信息,这样主页ViewModel能拿到用户名:

// 用于传递用户信息的实体类
public class UserInfo
{
    public string Username { get; set; }
    // 可根据需求添加其他字段,比如用户ID、角色等
}

// 登录成功事件
public class UserLoggedInEvent : PubSubEvent<UserInfo>
{
}

2. 在LoginViewModel中发布事件

登录验证通过后,利用IEventAggregator发布事件,同时传递用户信息:

using Prism.Commands;
using Prism.Events;
using Prism.Mvvm;
using Prism.Navigation;
using System.Windows;

public class LoginViewModel : BindableBase
{
    private readonly IEventAggregator _eventAggregator;
    private readonly INavigationService _navigationService;

    private string _username;
    public string Username
    {
        get => _username;
        set => SetProperty(ref _username, value);
    }

    private string _password;
    public string Password
    {
        get => _password;
        set => SetProperty(ref _password, value);
    }

    public DelegateCommand LoginCommand { get; }

    public LoginViewModel(IEventAggregator eventAggregator, INavigationService navigationService)
    {
        _eventAggregator = eventAggregator;
        _navigationService = navigationService;
        LoginCommand = new DelegateCommand(ExecuteLogin);
    }

    private void ExecuteLogin()
    {
        // 替换为你的实际登录验证逻辑(比如调用后端接口、数据库校验)
        if (ValidateCredentials())
        {
            // 发布登录成功事件,传递当前用户信息
            _eventAggregator.GetEvent<UserLoggedInEvent>()
                .Publish(new UserInfo { Username = Username });
            
            // 这里也可以直接导航,但用事件更解耦,让主页自己处理显示逻辑
            // _navigationService.NavigateAsync("MainHomeView");
        }
        else
        {
            MessageBox.Show("用户名或密码错误,请重试!");
        }
    }

    private bool ValidateCredentials()
    {
        // 模拟验证,实际开发中替换为真实逻辑
        return !string.IsNullOrWhiteSpace(Username) && Password == "123456";
    }
}

3. 主页ViewModel监听并处理事件

在主页ViewModel中订阅UserLoggedInEvent,收到事件后更新用户名并触发主页显示:

using Prism.Commands;
using Prism.Events;
using Prism.Mvvm;
using Prism.Navigation;
using System.Windows;

public class MainHomeViewModel : BindableBase, IInitialize
{
    private readonly IEventAggregator _eventAggregator;
    private readonly INavigationService _navigationService;
    private SubscriptionToken _loginEventToken;

    private string _currentUsername;
    public string CurrentUsername
    {
        get => _currentUsername;
        set => SetProperty(ref _currentUsername, value);
    }

    public DelegateCommand ActionButtonCommand { get; }

    public MainHomeViewModel(IEventAggregator eventAggregator, INavigationService navigationService)
    {
        _eventAggregator = eventAggregator;
        _navigationService = navigationService;
        ActionButtonCommand = new DelegateCommand(ExecuteAction);
    }

    public void Initialize(INavigationParameters parameters)
    {
        // 订阅登录成功事件,使用SubscriptionToken方便后续取消订阅
        _loginEventToken = _eventAggregator.GetEvent<UserLoggedInEvent>()
            .Subscribe(OnUserLoggedIn);
    }

    private void OnUserLoggedIn(UserInfo userInfo)
    {
        // 更新绑定的用户名
        CurrentUsername = userInfo.Username;
        // 导航到主页(如果启动时默认加载的是登录页,这里切换到主页)
        _navigationService.NavigateAsync("MainHomeView");
    }

    private void ExecuteAction()
    {
        // 主页按钮的业务逻辑示例
        MessageBox.Show($"你好,{CurrentUsername}!已执行操作。");
    }

    // 可选:手动取消订阅(Prism默认用弱引用,ViewModel销毁时会自动取消,手动更稳妥)
    public void Cleanup()
    {
        if (_loginEventToken != null)
        {
            _eventAggregator.GetEvent<UserLoggedInEvent>().Unsubscribe(_loginEventToken);
        }
    }
}

4. 配置启动导航与视图注册

在App.xaml.cs中设置启动时默认导航到登录页,并注册所有视图:

using Prism.Ioc;
using Prism.Regions;
using System.Windows;

public partial class App
{
    protected override Window CreateShell()
    {
        return Container.Resolve<MainWindow>(); // 你的Shell窗口
    }

    protected override void OnInitialized()
    {
        base.OnInitialized();
        // 启动时导航到登录页
        var regionManager = Container.Resolve<IRegionManager>();
        regionManager.RequestNavigate("ContentRegion", "LoginView");
    }

    protected override void RegisterTypes(IContainerRegistry containerRegistry)
    {
        // 注册视图与ViewModel的关联
        containerRegistry.RegisterForNavigation<LoginView, LoginViewModel>();
        containerRegistry.RegisterForNavigation<MainHomeView, MainHomeViewModel>();
        
        // Prism默认已注册IEventAggregator,无需手动注册
    }
}

5. 主页视图绑定数据

最后在MainHomeView.xaml中绑定用户名和按钮命令:

<UserControl x:Class="YourAppNamespace.MainHomeView"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:prism="http://prismlibrary.com/"
             prism:ViewModelLocator.AutoWireViewModel="True">
    <Grid>
        <StackPanel HorizontalAlignment="Center" VerticalAlignment="Center" Spacing="15">
            <TextBlock FontSize="22">欢迎回来,</TextBlock>
            <TextBlock Text="{Binding CurrentUsername}" FontSize="28" FontWeight="Bold"/>
            <Button Content="执行操作" Command="{Binding ActionButtonCommand}" Width="140" Height="45"/>
        </StackPanel>
    </Grid>
</UserControl>

一些注意事项

  • 解耦性:用事件聚合器而不是直接在LoginViewModel中导航,能让登录模块和主页模块完全独立,后续修改主页逻辑不会影响登录模块。
  • 内存泄漏:Prism的PubSubEvent默认使用弱引用订阅,所以即使不手动取消订阅,当ViewModel被销毁时订阅会自动释放,不用担心内存泄漏;如果需要手动控制,使用SubscriptionToken取消订阅即可。
  • 登录验证:一定要把示例中的模拟验证替换为真实的业务逻辑(比如调用后端API、访问数据库),不要在客户端硬编码凭证。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.20 07:10:47