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

.NET MAUI Android端默认返回按钮行为修改:页面与VM重置需求

.NET MAUI MVVM页面返回后未销毁导致重复执行问题解决

问题现象

使用MVVM模式开发Android平台的.NET MAUI应用,从主页导航至Warehouse子页面后,点击顶部默认返回箭头回到主页,发现页面及关联ViewModel未被销毁:

  • ViewModel中通过MessagingCenter订阅扫码事件,每次进入子页面都会新增订阅,导致扫码后SQL Server插入操作重复执行
  • DisplayAlert弹窗的显示次数随进入子页面的次数递增

现有代码

AppShell路由注册

public AppShell()
{
    InitializeComponent();
    Routing.RegisterRoute(nameof(Warehouse), typeof(Warehouse));
}

Warehouse页面代码后置

public partial class Warehouse: ContentPage
{
    private WarehouseViewModel ICvm;
    public Warehouse()
    {
        InitializeComponent();
        ICvm = new WarehouseViewModel();
        BindingContext = ICvm;
    }
}

主页导航代码

await Shell.Current.GoToAsync(nameof(Warehouse));

WarehouseViewModel代码

internal class WarehouseViewModel: INotifyPropertyChanged
{
    public WarehouseViewModel()
    {
        MessagingCenter.Subscribe<object, string>(this, "ScannedBarcodeFromMainActivity", async (sender, ScannedBarcode) =>
        {
            ScannedBarcodeReceived = ScannedBarcode;
            bool Insertion_To_DB_Outcome = await MyApiService.Set_PC(ScannedBarcodeReceived);
            if (!Insertion_To_DB_Outcome)
            {
                await App.Current.MainPage.DisplayAlert("Error while inserting", "error while inserting to db :(", "OK");
            }
            else
            {
                await App.Current.MainPage.DisplayAlert("Success","Success inserting to db", "OK");
            }
        });
    }

    // INotifyPropertyChanged 实现代码省略
    public event PropertyChangedEventHandler PropertyChanged;
}

解决方案

核心问题是ViewModel的MessagingCenter订阅未取消,且页面返回时ViewModel未被正确释放,导致多个ViewModel实例同时存在并响应事件。

1. 让ViewModel实现IDisposable接口取消订阅

修改WarehouseViewModel,实现IDisposable接口,在Dispose方法中取消MessagingCenter订阅:

internal class WarehouseViewModel : INotifyPropertyChanged, IDisposable
{
    public WarehouseViewModel()
    {
        MessagingCenter.Subscribe<object, string>(this, "ScannedBarcodeFromMainActivity", async (sender, ScannedBarcode) =>
        {
            ScannedBarcodeReceived = ScannedBarcode;
            bool Insertion_To_DB_Outcome = await MyApiService.Set_PC(ScannedBarcodeReceived);
            if (!Insertion_To_DB_Outcome)
            {
                await App.Current.MainPage.DisplayAlert("Error while inserting", "error while inserting to db :(", "OK");
            }
            else
            {
                await App.Current.MainPage.DisplayAlert("Success", "Success inserting to db", "OK");
            }
        });
    }

    public void Dispose()
    {
        // 取消订阅,避免内存泄漏和重复响应
        MessagingCenter.Unsubscribe<object, string>(this, "ScannedBarcodeFromMainActivity");
    }

    // INotifyPropertyChanged 实现代码
    public event PropertyChangedEventHandler PropertyChanged;
    protected void OnPropertyChanged(string propertyName)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

2. 在页面返回时释放ViewModel

修改Warehouse页面,在返回导航时销毁ViewModel并释放资源:

public partial class Warehouse : ContentPage
{
    private WarehouseViewModel ICvm;
    public Warehouse()
    {
        InitializeComponent();
        ICvm = new WarehouseViewModel();
        BindingContext = ICvm;
    }

    protected override void OnNavigatedFrom(NavigatedFromEventArgs args)
    {
        base.OnNavigatedFrom(args);
        // 仅当返回导航时清理资源
        if (args.NavigationMode == NavigationMode.Back)
        {
            ICvm?.Dispose();
            ICvm = null;
            BindingContext = null;
        }
    }
}

3. 可选:禁用Shell页面缓存(按需)

如果需要彻底销毁页面实例,可以在路由注册时禁用Shell的页面缓存:

public AppShell()
{
    InitializeComponent();
    Routing.RegisterRoute(nameof(Warehouse), typeof(Warehouse), new ShellNavigationQueryParameters
    {
        { "ShellNavigationCacheMode", ShellNavigationCacheMode.Disabled }
    });
}

这样每次进入Warehouse页面都会创建新实例,返回时直接销毁,避免缓存导致的实例残留。

内容的提问来源于stack exchange,提问作者taqasar-elcam

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.04 11:07:34