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

.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;
}

问题排查与修复方案

核心原因

  1. Shell导航路径格式错误:///DrawPage的绝对路径格式不符合Shell路由规范,无法正确匹配注册页面
  2. 属性未实现变更通知:DrawingId属性未触发PropertyChanged事件,Shell设置参数后页面无法及时感知
  3. 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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.15 20:40:00