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

在.NET MAUI Shell(MVVM)中,如何不使用QueryProperty或公共setter接收导航数据?

.NET MAUI Shell导航:规避QueryProperty与公共可变属性的MVVM实践

推荐模式1:ViewModel工厂+构造注入

这种模式通过自定义ViewModel工厂,从Shell导航参数中提取数据后直接注入目标ViewModel的构造函数,无需暴露公共可变属性,完全契合构造注入的MVVM设计原则。

步骤示例:

  1. 定义ViewModel工厂接口:
public interface IViewModelFactory
{
    T Create<T>(IDictionary<string, object> parameters = null);
}
  1. 实现工厂类,根据导航参数创建ViewModel:
public class ViewModelFactory : IViewModelFactory
{
    private readonly IServiceProvider _serviceProvider;

    public ViewModelFactory(IServiceProvider serviceProvider)
    {
        _serviceProvider = serviceProvider;
    }

    public T Create<T>(IDictionary<string, object> parameters = null)
    {
        var viewModelType = typeof(T);
        if (parameters != null && viewModelType == typeof(ProductDetailViewModel))
        {
            if (parameters.TryGetValue("product", out var product) && product is Product selectedProduct)
            {
                return (T)Activator.CreateInstance(viewModelType, selectedProduct);
            }
        }
        return _serviceProvider.GetRequiredService<T>();
    }
}
  1. 目标ViewModel通过构造函数接收数据:
public class ProductDetailViewModel : BaseViewModel
{
    private readonly Product _selectedProduct;

    public string ProductName => _selectedProduct.Name;
    public decimal ProductPrice => _selectedProduct.Price;

    public ProductDetailViewModel(Product selectedProduct)
    {
        _selectedProduct = selectedProduct;
    }
}
  1. 页面中通过工厂绑定ViewModel:
public partial class ProductDetailPage : ContentPage
{
    public ProductDetailPage(IViewModelFactory viewModelFactory)
    {
        InitializeComponent();
        if (Navigation.CurrentPage?.NavigationParameter is IDictionary<string, object> parameters)
        {
            BindingContext = viewModelFactory.Create<ProductDetailViewModel>(parameters);
        }
    }
}

推荐模式2:导航感知ViewModel(内部参数提取)

让ViewModel实现自定义导航感知接口,在导航完成后直接从参数中提取数据,仅保留业务所需的私有可绑定属性。

步骤示例:

  1. 定义导航感知接口:
public interface INavigatedAware
{
    void OnNavigatedTo(IDictionary<string, object> parameters);
}
  1. 目标ViewModel实现接口并处理参数:
public class ProductDetailViewModel : BaseViewModel, INavigatedAware
{
    private string _productName;
    public string ProductName
    {
        get => _productName;
        private set => SetProperty(ref _productName, value);
    }

    private decimal _productPrice;
    public decimal ProductPrice
    {
        get => _productPrice;
        private set => SetProperty(ref _productPrice, value);
    }

    public void OnNavigatedTo(IDictionary<string, object> parameters)
    {
        if (parameters.TryGetValue("product", out var product) && product is Product selectedProduct)
        {
            ProductName = selectedProduct.Name;
            ProductPrice = selectedProduct.Price;
        }
    }
}
  1. 页面中传递导航参数到ViewModel:
public partial class ProductDetailPage : ContentPage
{
    public ProductDetailPage(ProductDetailViewModel viewModel)
    {
        InitializeComponent();
        BindingContext = viewModel;
    }

    protected override void OnNavigatedTo(NavigatedToEventArgs args)
    {
        base.OnNavigatedTo(args);
        if (args.Parameter is IDictionary<string, object> parameters && BindingContext is INavigatedAware navigatedAware)
        {
            navigatedAware.OnNavigatedTo(parameters);
        }
    }
}

推荐模式3:WeakReferenceMessenger消息传递

使用.NET MAUI内置的WeakReferenceMessenger(替代过时的MessagingCenter),通过消息传递导航数据,适合松散耦合的场景,需注意订阅清理避免内存泄漏。

步骤示例:

  1. 定义导航消息类型:
public class ProductNavigationMessage : ValueChangedMessage<Product>
{
    public ProductNavigationMessage(Product product) : base(product)
    {
    }
}
  1. 发起导航时发送消息:
await Shell.Current.GoToAsync(nameof(ProductDetailPage));
WeakReferenceMessenger.Default.Send(new ProductNavigationMessage(selectedProduct));
  1. 目标ViewModel订阅消息并处理:
public class ProductDetailViewModel : BaseViewModel
{
    private string _productName;
    public string ProductName
    {
        get => _productName;
        private set => SetProperty(ref _productName, value);
    }

    private decimal _productPrice;
    public decimal ProductPrice
    {
        get => _productPrice;
        private set => SetProperty(ref _productPrice, value);
    }

    public ProductDetailViewModel()
    {
        WeakReferenceMessenger.Default.Register<ProductNavigationMessage>(this, (r, m) =>
        {
            var selectedProduct = m.Value;
            ProductName = selectedProduct.Name;
            ProductPrice = selectedProduct.Price;
        });
    }

    public void Cleanup()
    {
        WeakReferenceMessenger.Default.Unregister<ProductNavigationMessage>(this);
    }
}
  1. 页面销毁时清理订阅:
protected override void OnDisappearing()
{
    base.OnDisappearing();
    if (BindingContext is ProductDetailViewModel viewModel)
    {
        viewModel.Cleanup();
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.11 18:05:10