2

When I try navigating to the page without passing an argument, everything works as expected. As soon as I pass a Dictionary into the Method I get a weird exception with "The application is in break mode Your app has entered a break state, but there is no code to show because all threads were executing external code (typically system or framework code)."

Command that executes the navigation:

[RelayCommand]
async Task OpenEntry(Training training)
{
    //This navigates to page
    //await Shell.Current.GoToAsync(nameof(DetailPage));
    //This doesnt navigate to page and throws: System.InvalidCastException: 'Object must implement IConvertible.'
    await Shell.Current.GoToAsync(
        nameof(DetailPage), 
        true, 
        new Dictionary<string, object>() 
        { 
            { "DetailTraining", (Training)training } 
        });
}

Viewmodel of page I want to navigate to:

[QueryProperty(nameof(DetailedTraining),"DetailTraining")]
public partial class DetailViewModel : ObservableObject
{
    [ObservableProperty]
    Training detailedTraining;

    public DetailViewModel()
    {}
}

Callstack of exception:

0xFFFFFFFFFFFFFFFF in Android.Runtime.JNIEnv.monodroid_debugger_unhandled_exception C#
0x1A in Android.Runtime.JNINativeWrapper._unhandled_exception at /Users/runner/work/1/s/xamarin-android/src/Mono.Android/Android.Runtime/JNINativeWrapper.g.cs:12,5 C#
0x1D in Android.Runtime.JNINativeWrapper.Wrap_JniMarshal_PP_V at /Users/runner/work/1/s/xamarin-android/src/Mono.Android/Android.Runtime/JNINativeWrapper.g.cs:23,26    C#
0x17 in System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw    C#
0x6 in System.Threading.Tasks.Task.<>c.<ThrowAsync>b__128_0 C#
0xC in Android.App.SyncContext. at /Users/runner/work/1/s/xamarin-android/src/Mono.Android/Android.App/SyncContext.cs:36,19 C#
0xE in Java.Lang.Thread.RunnableImplementor.Run at /Users/runner/work/1/s/xamarin-android/src/Mono.Android/Java.Lang/Thread.cs:36,6 C#
0x8 in Java.Lang.IRunnableInvoker.n_Run at /Users/runner/work/1/s/xamarin-android/src/Mono.Android/obj/Release/net7.0/android-33/mcw/Java.Lang.IRunnable.cs:84,4    C#
0x8 in Android.Runtime.JNINativeWrapper.Wrap_JniMarshal_PP_V at /Users/runner/work/1/s/xamarin-android/src/Mono.Android/Android.Runtime/JNINativeWrapper.g.cs:22,5  C#

As I said, I think I have the Routing and the Dependencies set up correctly because simple navigation without passing an object works just fine.

I have also tried passing a string to the page like this:

await Shell.Current.GoToAsync($"{nameof(DetailPage)}?Text={training.Name}");

Then I adjusted the QueryProperty: [QueryProperty("Text","Text")] I also added to the viewmodel: [ObservableProperty] text; When I tried passing a string like this I had no problem and everything worked as expected.

But as soon as I try using the overload public Task GoToAsync(ShellNavigationState state, IDictionary<string, object> parameters); the application crashes and Visual Studio 2022 shows me the "Your application is in break mode" screen and a exception popup with "System.InvalidCastException: 'Object must implement IConvertible.'".

All of this is happening when I run it on the Android simulator. When I try running it on Windows, it breaks in the "App.g.i.cs" (Autogenerated file) in this if clause:

#if DEBUG && !DISABLE_XAML_GENERATED_BREAK_ON_UNHANDLED_EXCEPTION
    UnhandledException += (sender, e) =>
    {
        if (global::System.Diagnostics.Debugger.IsAttached) global::System.Diagnostics.Debugger.Break();
    };
#endif

Also tried the hack of @ToolmakerSteve from this post: Maui shell navigation fails - rare reproduction but this just makes the windows variant also immediately show me the "System.InvalidCastException" popup instead of breaking in the auto generated file Thanks in Advance!

1 Answer 1

4

You're mixing up string-based query parameters and object-based navigation parameters.

String-based query parameters

You can pass the training object as a query parameter, provided that it is a string:

await Shell.Current.GoToAsync(
    $"{nameof(DetailPage)}?DetailTraining={training}&Duration={10}",
    true);

In your ViewModel or Page, you can then use the [QueryProperty] attribute to receive the properties:

[QueryProperty(nameof(DetailedTraining),"DetailTraining")]
[QueryProperty(nameof(Duration), nameof(Duration)]
public partial class DetailViewModel : ObservableObject
{
    [ObservableProperty]
    string detailedTraining;

    [ObservableProperty]
    int duration;
}

This uses the string-based query parameters approach.

Note: This only works with simple value types like string, int and bool.

Object-based navigation parameters

If you want to use the object-based navigation parameters approach to pass objects of your own classes and types, you'll need to implement the IQueryAttributable interface on your receiving class, e.g. your ViewModel:

public partial class DetailViewModel : ObservableObject, IQueryAttributable
{
    [ObservableProperty]
    Training detailedTraining;

    public void ApplyQueryAttributes(IDictionary<string, object> query)
    {
        DetailedTraining = query["DetailTraining"] as Training;
    }
}
Sign up to request clarification or add additional context in comments.

2 Comments

Your first approach threw me this exception: System.InvalidCastException: 'Invalid cast from 'System.String' to 'xxx.Models.Training' The second approach worked when I added OnPropertyChanged("DetailedTraining"); to the method. I was under the impression that the QueryPropertyAttribute will generate this method for me automatically like the [ObservableProperty] attribute.
Ah yes, that's because you're not passing a simple data type such as string, int or bool. I've updated the answer to avoid confusion. The [ObservableProperty] uses a Source Generator, the [QueryProperty] attribute does not.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.