Xamarin中InitializeComponent()触发NullReferenceException问题求助
我是Xamarin新手,尝试通过MVVM模式读取Editor/Entry的值,但每次启动代码打开页面时,InitializeComponent()都会触发NullReferenceException。我已将Editor的Text绑定到ViewModel中的属性,并在XAML中引用了命名空间,查阅文档及示例代码后仍无法解决问题,附上相关代码,恳请帮忙排查。
XAML代码
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" xmlns:local="clr-namespace:student_app.ViewModels" x:Class="student_app.Views.AddCategoryPage" xmlns:model="clr-namespace:student_app.Models" > <ContentPage.BindingContext> <local:AddCategoryViewModel/> </ContentPage.BindingContext> <RefreshView x:DataType="local:AddCategoryViewModel" Command="{Binding LoadCategoriesCommand}" IsRefreshing="{Binding IsBusy, Mode=TwoWay}"> <StackLayout> <Label Text="Add Category:"/> <Editor Grid.Row="1" Grid.Column="0" Width="300" Text="{Binding CategoryNameEditor}" Placeholder="enter category name"/> <Button x:Name="saveButton" Text="Save" Command="{Binding SaveCommand}"/> </StackLayout> </RefreshView> </ContentPage>
页面后台代码
namespace student_app.Views { [XamlCompilation(XamlCompilationOptions.Compile)] public partial class AddCategoryPage : ContentPage { AddCategoryViewModel _viewModel; public AddCategoryPage() { InitializeComponent(); this.BindingContext = _viewModel = AppContainer.Resolve<AddCategoryViewModel>(); } protected override void OnAppearing() { base.OnAppearing(); _viewModel.OnAppearing(); } } }
ViewModel代码
namespace student_app.ViewModels { public class AddCategoryViewModel : BaseViewModel { private readonly IToastService _toastService; private readonly INavigationService _navigationService; private readonly ICategoryService _categoryService; public string categoryName; public Command SaveCommand { get; } public Command LoadCategoriesCommand { get; } public event PropertyChangingEventHandler PropertyChanged; public string CategoryNameEditor { get => categoryName; set { categoryName = value; var args = new PropertyChangingEventArgs(nameof(CategoryNameEditor)); PropertyChanged?.Invoke(this, args); } } public AddCategoryViewModel(IToastService toastService, INavigationService navigationService, ICategoryService categoryService) { _toastService = toastService; _navigationService = navigationService; _categoryService = categoryService; SaveCommand = new Command(async () => await ExecuteSaveCommandCommand()); LoadCategoriesCommand = new Command(async () => await ExecuteLoadCategoriesCommand()); } public async Task ExecuteLoadCategoriesCommand() { IsBusy = true; try { categoryName = string.Empty; } catch (Exception ex) { await _toastService.DisplayToastAsync(ex.Message); } finally { IsBusy = false; } } public async Task ExecuteSaveCommandCommand() { IsBusy = true; try { _categoryService.addCategory(categoryName); categoryName = string.Empty; await _navigationService.NavigateAsync("CalanderPage"); } catch (Exception ex) { await _toastService.DisplayToastAsync(ex.Message); } finally { IsBusy = false; } } public void OnAppearing() { IsBusy = true; } } }
问题排查与解决方案
1. BindingContext重复设置导致初始化失败
XAML中通过<ContentPage.BindingContext>尝试创建AddCategoryViewModel实例,但你的ViewModel仅提供了带三个依赖参数的构造函数,无参构造函数不存在,XAML初始化时无法创建实例,直接抛出NullReferenceException。同时后台代码又通过依赖注入重新设置了BindingContext,属于重复操作。
解决:删除XAML中的<ContentPage.BindingContext>节点,保留后台依赖注入的逻辑。
2. PropertyChanged事件类型错误
ViewModel中错误声明了PropertyChangingEventHandler类型的PropertyChanged事件,正确的应该是PropertyChangedEventHandler,且触发时需传入PropertyChangedEventArgs。如果继承的BaseViewModel已经实现了INotifyPropertyChanged接口,直接调用基类的OnPropertyChanged方法即可,无需自行声明事件。
修正示例:
// 移除自行声明的PropertyChanged事件,使用基类实现 public string CategoryNameEditor { get => categoryName; set { categoryName = value; OnPropertyChanged(nameof(CategoryNameEditor)); } }
3. 无效的布局属性
Editor控件设置了Grid.Row和Grid.Column属性,但它的父容器是StackLayout,这些属性不会生效,属于无效代码,建议移除。
4. 直接赋值字段未触发属性变更
在ExecuteLoadCategoriesCommand和ExecuteSaveCommandCommand中直接给categoryName字段赋值,不会触发PropertyChanged事件,导致UI无法同步更新。应改为给CategoryNameEditor属性赋值:
// 替换 categoryName = string.Empty; CategoryNameEditor = string.Empty;
内容的提问来源于stack exchange,提问作者user12496215

