如何通过AddTransient服务在.NET MAUI MVVM页面间传值
.NET MAUI CommunityToolkit MVVM 页面间传参(无需QueryProperty)
问题原因分析
你之前用ServiceHelper获取Page2ViewModel实例传值后页面绑定的VM为Null,核心原因是:你提前获取的VM实例和Page2导航时自动创建的VM实例不是同一个(因为注册的是Transient服务,每次获取都会生成新实例),导致传值的实例和页面绑定的实例脱节。
可行解决方案
方案1:构造函数传参(推荐,符合依赖注入规范)
这种方式直接在创建ViewModel时传入参数,确保页面绑定的实例就是已赋值的实例。
- 修改Page2ViewModel的构造函数,接收ID参数:
public class Page2ViewModel : ObservableObject { private int _id; public int Id { get => _id; set => SetProperty(ref _id, value); } // 带参数的构造函数 public Page2ViewModel(int id) { _id = id; } }
- 在MauiProgram中注册带参数的ViewModel工厂:
// 注册可传入ID的ViewModel工厂 builder.Services.AddTransient<Func<int, Page2ViewModel>>(sp => id => new Page2ViewModel(id)); // 同时保留基础注册(可选,根据导航方式调整) builder.Services.AddTransient<Page2ViewModel>(sp => new Page2ViewModel(0));
- 在Page1ViewModel中通过工厂创建VM并导航:
public class Page1ViewModel : ObservableObject { private readonly INavigationService _navigationService; private readonly IServiceProvider _serviceProvider; public RelayCommand<int> NavigateToPage2Command { get; } public Page1ViewModel(INavigationService navigationService, IServiceProvider serviceProvider) { _navigationService = navigationService; _serviceProvider = serviceProvider; NavigateToPage2Command = new RelayCommand<int>(NavigateToPage2); } private void NavigateToPage2(int id) { // 通过工厂创建带ID的Page2ViewModel var vmFactory = _serviceProvider.GetRequiredService<Func<int, Page2ViewModel>>(); var page2Vm = vmFactory(id); // 创建Page2并绑定ViewModel var page2 = new Page2 { BindingContext = page2Vm }; // 执行导航 _navigationService.PushAsync(page2); } }
方案2:页面生命周期传参
通过页面的导航事件获取参数,直接传递给绑定的ViewModel。
- Page1ViewModel导航时携带参数:
private void NavigateToPage2(int id) { var navParams = new Dictionary<string, object> { { "TargetId", id } }; _navigationService.PushAsync(nameof(Page2), navParams); }
- 在Page2的后台代码中接收参数并传递给ViewModel:
protected override void OnNavigatedTo(NavigatedToEventArgs args) { base.OnNavigatedTo(args); if (args.Parameter is Dictionary<string, object> parameters && parameters.TryGetValue("TargetId", out var idObj) && idObj is int targetId) { if (BindingContext is Page2ViewModel vm) { vm.Id = targetId; // 若有初始化方法可直接调用:vm.Initialize(targetId); } } }
方案3:消息传递(CommunityToolkit自带)
利用WeakReferenceMessenger实现跨ViewModel的参数传递,适合完全解耦的场景。
- 定义消息类:
public class IdTransferMessage : ValueChangedMessage<int> { public IdTransferMessage(int value) : base(value) { } }
- Page1ViewModel发送消息并导航:
private void NavigateToPage2(int id) { WeakReferenceMessenger.Default.Send(new IdTransferMessage(id)); _navigationService.PushAsync(nameof(Page2)); }
- Page2ViewModel接收消息并赋值:
public class Page2ViewModel : ObservableObject { private int _id; public int Id { get => _id; set => SetProperty(ref _id, value); } public Page2ViewModel() { // 注册消息监听 WeakReferenceMessenger.Default.Register<IdTransferMessage>(this, (recipient, message) => { Id = message.Value; }); } // 销毁时注销监听,避免内存泄漏 ~Page2ViewModel() { WeakReferenceMessenger.Default.Unregister<IdTransferMessage>(this); } }
内容的提问来源于stack exchange,提问作者przepiora87
相关产品推荐
相关产品推荐

