.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
相关产品推荐
相关产品推荐

