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

MAUI Shell导航后视图未更新,MVVM模式下如何解决?

MAUI Shell MVVM模式下添加记录后刷新交易列表的解决方案

你的问题根源在于Shell的Tab页面默认会被缓存,TransactionsViewModel的构造函数只在页面首次加载时执行一次,添加新记录后缓存的集合不会自动更新。下面提供几种符合MVVM规范的解决方案:

方案1:通过页面显示事件触发ViewModel刷新

利用TransactionsPage的Appearing事件,每次页面切换回来时主动刷新数据:

第一步:给ViewModel添加刷新方法

修改TransactionsViewModel,把初始化数据的逻辑抽成独立方法,方便重复调用:

public partial class TransactionsViewModel: ObservableObject
{
    public TransactionsViewModel()
    {
        LoadTransactions();
    }

    [ObservableProperty]
    ObservableCollection<Transaction> transactions;

    // 新增刷新方法
    public void LoadTransactions()
    {
        var latestTransactions = App.TransactionRepository.GetAllTransactions();
        // 清空现有集合再添加新数据,避免重新创建集合导致绑定失效
        Transactions.Clear();
        foreach (var trans in latestTransactions)
        {
            Transactions.Add(trans);
        }
        // 也可以直接替换集合:Transactions = new ObservableCollection<Transaction>(latestTransactions);
        // 因为用了[ObservableProperty],替换时会自动触发属性变更通知
    }
}

第二步:在页面中订阅显示事件

修改TransactionsPage,每次页面显示时调用ViewModel的刷新方法:

public partial class TransactionsPage : ContentPage
{
    private readonly TransactionsViewModel _viewModel;

    public TransactionsPage(TransactionsViewModel vm)
    {
        InitializeComponent();
        _viewModel = vm;
        BindingContext = vm;
        // 订阅页面显示事件
        Appearing += OnPageAppearing;
    }

    private void OnPageAppearing(object sender, EventArgs e)
    {
        _viewModel.LoadTransactions();
    }

    // 取消订阅避免内存泄漏
    protected override void OnDisappearing()
    {
        base.OnDisappearing();
        Appearing -= OnPageAppearing;
    }
}

方案2:用弱引用信使实现跨ViewModel通知刷新

这种方式更符合MVVM的解耦要求,添加新记录后主动通知交易列表ViewModel更新:

第一步:定义消息类

新建一个消息类,用来传递新增交易的信息:

public class TransactionAddedMessage
{
    public Transaction NewTransaction { get; set; }
}

第二步:在添加页ViewModel发送消息

假设你的添加页ViewModel是AddNewViewModel,保存后发送消息:

public partial class AddNewViewModel : ObservableObject
{
    [ObservableProperty]
    Transaction newTransaction;

    [RelayCommand]
    void SaveTransaction()
    {
        // 保存到仓库
        App.TransactionRepository.AddTransaction(NewTransaction);
        // 发送新增交易的消息
        WeakReferenceMessenger.Default.Send(new TransactionAddedMessage { NewTransaction = NewTransaction });
        // 如果是通过导航跳转而不是Tab切换,这里可以添加导航代码
        // await Shell.Current.GoToAsync(nameof(TransactionsPage));
    }
}

第三步:在交易列表ViewModel订阅消息

修改TransactionsViewModel,订阅消息并更新集合:

public partial class TransactionsViewModel: ObservableObject
{
    public TransactionsViewModel()
    {
        LoadTransactions();
        // 订阅新增交易的消息
        WeakReferenceMessenger.Default.Register<TransactionAddedMessage>(this, (recipient, message) =>
        {
            // 直接把新交易加到集合里,不用重新查询所有数据
            Transactions.Add(message.NewTransaction);
            // 如果需要同步其他修改(比如删除、编辑),可以调用LoadTransactions()重新加载全部数据
            // LoadTransactions();
        });
    }

    [ObservableProperty]
    ObservableCollection<Transaction> transactions;

    public void LoadTransactions()
    {
        Transactions = new ObservableCollection<Transaction>(App.TransactionRepository.GetAllTransactions());
    }

    // 取消订阅避免内存泄漏
    ~TransactionsViewModel()
    {
        WeakReferenceMessenger.Default.Unregister<TransactionAddedMessage>(this);
    }
}

方案3:禁用页面缓存(不推荐)

如果不需要缓存交易页面,可以修改Shell的CacheMode,每次切换都重新创建页面和ViewModel:

<TabBar>
    <Tab Title="Transactions">
        <ShellContent ContentTemplate="{DataTemplate views:TransactionsPage}" CacheMode="NotCached" />
    </Tab>
    <Tab Title="Add New">
        <ShellContent ContentTemplate="{DataTemplate views:AddNewPage}" />
    </Tab>
</TabBar>

注意:这种方式会导致每次切换页面都重新初始化,频繁切换会影响性能,仅适合数据量极小的场景。


内容的提问来源于stack exchange,提问作者Pablo Aguirre de Souza

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.21 14:09:21