.NET MAUI中QueryProperty无法传递DrawingId至DrawPage问题求助
.NET MAUI Firestore绘图应用:DrawingId导航传递失败问题排查与修复
问题背景
我正在使用.NET MAUI和Firestore开发绘图应用:在HomePage页面展示现有绘图列表,选中某一绘图时,需导航至DrawPage打开该绘图进行修改。但发现DrawingId无法正确传递至DrawPage:HomePage中可正确识别DrawingId,但导航后DrawPage接收不到该参数。此外,DrawPage同时支持创建新绘图,此时无需ID即可完成初始化。
相关代码片段
HomePage.xaml.cs
public partial class HomePage : ContentPage { public HomePage(HomeViewModel viewModel) { InitializeComponent(); BindingContext = viewModel; // 页面显示时加载绘图 this.Appearing += async (s, e) => await viewModel.LoadUserDrawingsAsync(); } private async void OnDrawingSelected(object sender, SelectionChangedEventArgs e) { if (e.CurrentSelection.FirstOrDefault() is DrawingData selectedDrawing) { //Shell.Current.GoToAsync($"DrawPage?drawingId={selectedDrawing.Id}"); await Shell.Current.GoToAsync($"///DrawPage", new Dictionary<string, object> { { "DrawingId", selectedDrawing.Id } }); ((CollectionView)sender).SelectedItem = null; } } }
DrawPage.xaml.cs
[QueryProperty(nameof(DrawingId), "DrawingId")] public partial class DrawPage : ContentPage { private readonly DrawableCanvas _drawableCanvas; private readonly DrawViewModel _viewModel; public string DrawingId { get; set; } public DrawPage(DrawViewModel viewModel, FirestoreService firestoreService, FirebaseAuthClient firebaseClient) { InitializeComponent(); _drawableCanvas = new DrawableCanvas(); _viewModel = new DrawViewModel(_drawableCanvas, firestoreService, firebaseClient); BindingContext = _viewModel; DrawingCanvas.Drawable = _drawableCanvas; DrawingCanvas.StartInteraction += OnInteractionStart; DrawingCanvas.DragInteraction += OnInteractionDrag; } protected override async void OnAppearing() { base.OnAppearing(); if (!string.IsNullOrEmpty(DrawingId)) { Console.WriteLine($"DrawingId: {DrawingId}"); // 调试日志 await _viewModel.LoadDrawingAsync(DrawingId); } else { Console.WriteLine("DrawingId为空或null!"); } } private void OnInteractionStart(object sender, TouchEventArgs e) { if (e.Touches.Any()) { _drawableCanvas.StartNewLine(_viewModel.CurrentColor, _viewModel.LineThickness, _viewModel.Opacity); var touch = e.Touches.First(); _drawableCanvas.AddPoint(new PointF((float)touch.X, (float)touch.Y)); DrawingCanvas.Invalidate(); } } private void OnInteractionDrag(object sender, TouchEventArgs e) { if (e.Touches.Any()) { var touch = e.Touches.First(); _drawableCanvas.AddPoint(new PointF((float)touch.X, (float)touch.Y)); DrawingCanvas.Invalidate(); } } }
DrawViewModel.cs 加载方法
public async Task LoadDrawingAsync(string drawingId) { try { var userId = _authClient.User.Uid; var lines = await _firestoreService.LoadDrawingAsync(userId, drawingId); if (lines != null) { _drawableCanvas.Clear(); // 清除现有绘图 foreach (var line in lines) { var points = line.Points.Select(p => new PointF(p["X"], p["Y"])).ToList(); _drawableCanvas.AddLine(points, Color.FromHex(line.Color), line.Thickness, line.Opacity); } } } catch (Exception ex) { await Application.Current.MainPage.DisplayAlert("错误", $"加载绘图失败: {ex.Message}", "确定"); } }
FireStoreService.cs 加载方法
public async Task<List<LineData>> LoadDrawingAsync(string userId, string drawingId) { var drawingDoc = _firestoreDb.Collection("users") .Document(userId) .Collection("drawings") .Document(drawingId); var snapshot = await drawingDoc.GetSnapshotAsync(); if (!snapshot.Exists) return null; var lines = snapshot.GetValue<List<LineData>>("Lines"); return lines; }
问题排查与修复方案
核心原因
- Shell导航路径格式错误:
///DrawPage的绝对路径格式不符合Shell路由规范,无法正确匹配注册页面 - 属性未实现变更通知:
DrawingId属性未触发PropertyChanged事件,Shell设置参数后页面无法及时感知 - ViewModel实例化错误:DrawPage构造函数忽略了依赖注入传入的ViewModel,重新创建实例导致上下文混乱
修复步骤
1. 修正Shell导航代码
使用标准路由名称传递参数,替换HomePage中的导航逻辑:
private async void OnDrawingSelected(object sender, SelectionChangedEventArgs e) { if (e.CurrentSelection.FirstOrDefault() is DrawingData selectedDrawing) { // 使用查询字符串传递参数,确保与QueryProperty的名称匹配 await Shell.Current.GoToAsync($"DrawPage?DrawingId={selectedDrawing.Id}"); ((CollectionView)sender).SelectedItem = null; } }
2. 为DrawingId添加属性变更通知
修改DrawPage,实现INotifyPropertyChanged接口,确保参数值更新时能被及时捕获:
[QueryProperty(nameof(DrawingId), "DrawingId")] public partial class DrawPage : ContentPage, INotifyPropertyChanged { private string _drawingId; public string DrawingId { get => _drawingId; set { if (_drawingId != value) { _drawingId = value; OnPropertyChanged(); // 参数更新后直接触发加载逻辑 _ = LoadDrawingAsync(); } } } private async Task LoadDrawingAsync() { if (!string.IsNullOrEmpty(DrawingId)) { Console.WriteLine($"DrawingId: {DrawingId}"); await _viewModel.LoadDrawingAsync(DrawingId); } } // 保留其他原有代码... }
3. 正确注册Shell路由
在AppShell的构造函数中添加路由注册:
public AppShell() { InitializeComponent(); // 注册DrawPage路由 Routing.RegisterRoute(nameof(DrawPage), typeof(DrawPage)); }
4. 修复ViewModel实例化问题
直接使用依赖注入传入的ViewModel,避免重新创建:
public DrawPage(DrawViewModel viewModel, FirestoreService firestoreService, FirebaseAuthClient firebaseClient) { InitializeComponent(); _drawableCanvas = new DrawableCanvas(); // 使用传入的ViewModel,而非重新实例化 _viewModel = viewModel; // 为ViewModel绑定画布实例 _viewModel.SetDrawableCanvas(_drawableCanvas); BindingContext = _viewModel; DrawingCanvas.Drawable = _drawableCanvas; DrawingCanvas.StartInteraction += OnInteractionStart; DrawingCanvas.DragInteraction += OnInteractionDrag; }
同时在DrawViewModel中添加SetDrawableCanvas方法:
public void SetDrawableCanvas(DrawableCanvas canvas) { _drawableCanvas = canvas; }
验证修复
完成修改后重新运行应用:
- 选中HomePage中的绘图,查看控制台是否输出正确的DrawingId
- 确认目标绘图能正常加载显示
- 测试无ID时的新绘图创建流程,确保初始化正常
内容的提问来源于stack exchange,提问作者Szilvia Szepesi
相关产品推荐
相关产品推荐

