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

如何在Xamarin.Forms项目中借助MVVM Light实现ViewModel间数据传递

嘿,我正好在类似的Xamarin.Forms + MvvmLight项目里处理过这个需求,给你几个实用的方案,都是适配你的场景的:

方法1:利用MvvmLight的Messenger(消息传递)

这是MvvmLight最常用的跨ViewModel通信方式,完全解耦,非常适合你的列表项传值场景。

步骤如下:

  1. 先在你的.NET Standard共享项目里定义一个消息类,用来承载要传递的对象:
public class ItemSelectedMessage
{
    // 把YourListItemModel替换成你实际的列表对象类型
    public YourListItemModel SelectedItem { get; set; }
}
  1. 在列表页面的ViewModel里,当用户选中/操作列表项时发送消息:
    假设你已经把ListView的SelectedItem绑定到了ViewModel的对应属性,那么可以这样写:
private YourListItemModel _selectedItem;
public YourListItemModel SelectedItem
{
    get => _selectedItem;
    set
    {
        Set(ref _selectedItem, value);
        if (value != null)
        {
            // 发送消息传递选中的对象
            Messenger.Default.Send(new ItemSelectedMessage { SelectedItem = value });
            // 可选:重置选中状态,避免重复触发选中事件
            SelectedItem = null;
        }
    }
}

如果是用RelayCommand绑定列表项的点击事件,也可以在命令的执行方法里发送消息。

  1. 在接收数据的目标ViewModel里,注册消息监听(推荐在构造函数里完成):
public TargetViewModel()
{
    // 注册监听ItemSelectedMessage类型的消息
    Messenger.Default.Register<ItemSelectedMessage>(this, message =>
    {
        // 拿到传递过来的对象,处理业务逻辑
        var receivedItem = message.SelectedItem;
        // 比如赋值给ViewModel的属性,绑定到页面控件展示
        CurrentItem = receivedItem;
    });
}
  1. 别忘了在ViewModel销毁时注销消息,避免内存泄漏:
    MvvmLight的ViewModelBase自带Cleanup方法,你可以重写它:
public override void Cleanup()
{
    Messenger.Default.Unregister<ItemSelectedMessage>(this);
    base.Cleanup();
}
方法2:通过NavigationService传递参数

如果你之前是用MvvmLight的INavigationService来切换页面的(就是你参考的那篇文章里的方式),那直接在导航时传参数更直接。

步骤:

  1. 在列表ViewModel里,导航到目标页面时传入列表项对象:
private RelayCommand<YourListItemModel> _itemTapCommand;
public RelayCommand<YourListItemModel> ItemTapCommand =>
    _itemTapCommand ?? (_itemTapCommand = new RelayCommand<YourListItemModel>(ExecuteItemTap));

private void ExecuteItemTap(YourListItemModel item)
{
    if (item == null) return;
    // 用NavigationService导航,第二个参数就是要传递的对象
    NavigationService.NavigateTo(nameof(TargetPage), item);
}

这里的RelayCommand可以直接绑定到ListView的ItemTapped事件,或者自定义的ItemCommand。

  1. 在目标ViewModel里获取参数:
    你的目标ViewModel需要注入INavigationService,然后可以通过两种方式获取参数:
  • 方式一:用GetAndRemoveParameter(会移除参数,避免重复获取)
public class TargetViewModel : ViewModelBase
{
    private readonly INavigationService _navigationService;
    private YourListItemModel _currentItem;

    public YourListItemModel CurrentItem
    {
        get => _currentItem;
        set => Set(ref _currentItem, value);
    }

    public TargetViewModel(INavigationService navigationService)
    {
        _navigationService = navigationService;
        // 获取并移除导航参数
        var parameter = _navigationService.GetAndRemoveParameter<YourListItemModel>(this);
        if (parameter != null)
        {
            CurrentItem = parameter;
        }
    }
}
  • 方式二:重写OnNavigatedTo方法(每次导航到页面都会触发)
public override void OnNavigatedTo(object parameter)
{
    base.OnNavigatedTo(parameter);
    if (parameter is YourListItemModel item)
    {
        CurrentItem = item;
    }
}
方法3:全局共享服务(适合简单场景)

如果你的项目规模不大,也可以用一个全局的服务类临时存储数据,这种方式最简单,但耦合度较高,不推荐大型项目使用。

  1. 创建一个共享数据类:
public class SharedDataService
{
    public YourListItemModel SelectedItem { get; set; }
}
  1. 在App.xaml.cs里注册为单例:
public partial class App : Application
{
    public static SharedDataService SharedData { get; } = new SharedDataService();
    // ...其他初始化代码
}
  1. 在列表ViewModel里赋值:
private void ExecuteItemTap(YourListItemModel item)
{
    App.SharedData.SelectedItem = item;
    NavigationService.NavigateTo(nameof(TargetPage));
}
  1. 在目标ViewModel里获取:
public TargetViewModel()
{
    CurrentItem = App.SharedData.SelectedItem;
    // 可选:用完后清空,避免残留数据影响下次使用
    App.SharedData.SelectedItem = null;
}
总结
  • 优先推荐方法1(Messenger):完全符合MVVM的解耦思想,适合大多数跨ViewModel通信场景。
  • 如果已经在用INavigationService做页面切换,方法2更贴合你的现有架构,流程更顺畅。
  • 方法3只适合小型项目或临时需求,大型项目尽量避免,因为会增加代码耦合度。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.19 10:31:59