Когда я пытаюсь перейти на страницу без передачи аргумента, все работает так, как ожидалось. Как только я передаю словарь в метод, я получаю странное исключение с "Приложение находится в режиме приостановки Ваше приложение находится в состоянии останова, но код для отображения отсутствует, так как все потоки выполняли внешний код (обычно код системы или платформы)».
Команда, которая выполняет навигацию:
[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 }
});
}
Модель просмотра страницы, к которой я хочу перейти:
[QueryProperty(nameof(DetailedTraining),"DetailTraining")]
public partial class DetailViewModel : ObservableObject
{
[ObservableProperty]
Training detailedTraining;
public DetailViewModel()
{}
}
Стек вызовов исключения:
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#
Как я уже сказал, я думаю, что маршрутизация и зависимости настроены правильно, потому что простая навигация без передачи объекта работает просто отлично.
Я также попытался передать строку на страницу следующим образом:
await Shell.Current.GoToAsync($"{nameof(DetailPage)}?Text = {training.Name}");
Затем я изменил QueryProperty:
[QueryProperty("Text","Text")]
Я также добавил в модель представления:
[ObservableProperty] text;
Когда я попытался передать такую строку, у меня не было проблем, и все работало, как и ожидалось.
Но как только я пытаюсь использовать перегрузку
public Task GoToAsync(ShellNavigationState state, IDictionary<string, object> parameters);
приложение аварийно завершает работу, и Visual Studio 2022 показывает мне экран «Ваше приложение находится в режиме приостановки» и всплывающее окно исключения с «System.InvalidCastException: «Объект должен реализовать IConvertible».
Все это происходит, когда я запускаю его на симуляторе Android. Когда я пытаюсь запустить его в Windows, он ломается в «App.g.i.cs» (автогенерируемый файл) в этом предложении if:
#if DEBUG && !DISABLE_XAML_GENERATED_BREAK_ON_UNHANDLED_EXCEPTION
UnhandledException += (sender, e) =>
{
if (global::System.Diagnostics.Debugger.IsAttached) global::System.Diagnostics.Debugger.Break();
};
#endif
Также попробовал взлом @ToolmakerSteve из этого поста: Навигация в оболочке Мауи не удалась - редкая репродукция но это просто делает вариант Windows также немедленно показывает мне всплывающее окно «System.InvalidCastException» вместо того, чтобы ломать автоматически сгенерированный файл Заранее спасибо!





Вы смешиваете параметры запроса на основе строк и параметры навигации на основе объектов.
Вы можете передать объект training в качестве параметра запроса при условии, что это string:
await Shell.Current.GoToAsync(
$"{nameof(DetailPage)}?DetailTraining = {training}&Duration = {10}",
true);
Затем в ViewModel или Page вы можете использовать атрибут [QueryProperty] для получения свойств:
[QueryProperty(nameof(DetailedTraining),"DetailTraining")]
[QueryProperty(nameof(Duration), nameof(Duration)]
public partial class DetailViewModel : ObservableObject
{
[ObservableProperty]
string detailedTraining;
[ObservableProperty]
int duration;
}
При этом используется подход строковых параметров запроса.
Примечание. Это работает только с простыми типами значений, такими как string, int и bool.
Если вы хотите использовать объектно-ориентированные параметры навигации для передачи объектов ваших собственных классов и типов, вам необходимо реализовать интерфейс IQueryAttributable в принимающем классе, например. ваша модель представления:
public partial class DetailViewModel : ObservableObject, IQueryAttributable
{
[ObservableProperty]
Training detailedTraining;
public void ApplyQueryAttributes(IDictionary<string, object> query)
{
DetailedTraining = query["DetailTraining"] as Training;
}
}
Ах да, это потому, что вы не передаете простой тип данных, такой как string, int или bool. Я обновил ответ, чтобы избежать путаницы. [ObservableProperty] использует генератор источника, а атрибут [QueryProperty] — нет.
Ваш первый подход вызвал у меня это исключение: System.InvalidCastException: 'Неверное приведение от 'System.String' к 'xxx.Models.Training' Второй подход сработал, когда я добавил OnPropertyChanged("DetailedTraining"); к методу. У меня сложилось впечатление, что QueryPropertyAttribute автоматически сгенерирует для меня этот метод, как атрибут [ObservableProperty].