#xamarin #xamarin.forms #xamarin.android
Вопрос:
Я разрабатываю приложение для Android с тремя страницами. Первый — это домашняя страница. С этой страницы вы можете нажать на нужный объект, и вы будете отправлены на страницу объекта с соответствующими изображениями, названием и описанием. Нажав на изображение, вы попадете на страницу, на которой показано увеличенное изображение, реагирующее на жесты пользователя (масштабирование и панорамирование).
Пока все работает. Проблема возникает, когда со страницы изображения я хочу вернуться на предыдущую страницу (содержащую информацию об объекте). Этой странице нужен идентификатор объекта для отображения функций, и, следовательно, со страницы изображения я запускаю следующий код, чтобы вернуться:
await Shell.Current.GoToAsync($"..?ObjectId={ObjectId}");
Но, несмотря на то, что я зарегистрировал все страницы (представления) в файле AppShell.xaml.cs, когда я пытаюсь вернуться, я получаю это исключение:
System.ArgumentException: 'Ambiguous routes matched for: //D_FAULT_TabBar11/D_FAULT_Tab6/HomePage/ObjectPage?ObjectId= matches found: //D_FAULT_TabBar11/D_FAULT_Tab6/HomePage/ObjectPage,//D_FAULT_TabBar11/D_FAULT_Tab6/HomePage/ObjectPage. Parameter name: uri'
Не могли бы вы, пожалуйста, помочь мне с этой проблемой? Я (почти) искал по всему Интернету, но не смог найти никакого полезного ответа. Заранее спасибо!
Обновить:
Это страница HomePageViewModel, на которой я выбираю объект в представлении коллекции. Метод OnObjectTap вызывается, когда пользователь нажимает на объект и выводит его на вкладку с информацией об объекте. Этот фрагмент кода работает
class HomePageViewModel : BindableObject {
public ICommand ObjectTapCollectionView { get; }
public HomePageViewModel () {
ObjectTapCollectionView = new Command(OnObjectTap);
}
private static ObservableCollection<MyObject> objectList = new ObservableCollection<MyObject>();
public ObservableCollection<MyObject> ObjectList {
get { return objectList ; }
set {
objectList = value;
OnPropertyChanged();
}
}
private MyObject selectedObject;
public MyObject SelectedObject {
get { return selectedObject; }
set { selectedObject = value; }
}
private async void OnObjectTap() {
await Shell.Current.GoToAsync($"{nameof(ObjectPage)}?ObjectId={selectedObject.Object_Id}");
}
}
Это страница ObjectViewModel. Параметр ‘ObjectId’ передается на эту страницу. Если пользователь нажимает на изображение объекта, он автоматически переходит на страницу полноэкранного изображения, с которой он может увеличить изображение.Этот фрагмент кода работает
[QueryProperty(nameof(ObjectId), nameof(ObjectId))]
class ObjectPage : BindableObject {
public ICommand ImageTapCarouselView { get; }
public ObjectViewModel () {
ImageTapCarouselView = new Command(OnImageTap);
}
private MyObject myObj = new MyObject ();
public MyObject MyObj {
get { return myObj ; }
set {
myObj = value;
OnPropertyChanged();
}
}
private String objectId = String.Empty;
public String ObjectId {
get { return objectId ; }
set {
objectId = Uri.UnescapeDataString(value ?? string.Empty);
//Trovo l'esercizio selezionato
MyObject = ObjectListService.objects.Find(x => x.Object_Id == ObjectId);
OnPropertyChanged();
}
}
private ObservableCollection<String> objectImageList = new ObservableCollection<String>();
public ObservableCollection<String> ObjectImageList {
get { return objectImageList ; }
set {
objectImageList = value;
OnPropertyChanged();
}
}
private async void OnImageTap(object obj) {
String imagePath = (String)obj;
await Shell.Current.GoToAsync($"{nameof(FullScreenImagePage)}?ObjectId={MyObj.Object_Id}amp;ImagePath={imagePath}");
}
}
Это страница FullScreenImageViewModel. Параметры «ObjectId» и «Путь к изображению» передаются на эту страницу из функции «OnImageTap» выше. Проблема здесь в том, что
[QueryProperty(nameof(ObjectId ), nameof(ObjectId ))]
[QueryProperty(nameof(ImagePath), nameof(ImagePath))]
class FullScreenImageViewModel : BindableObject {
public FullScreenImageViewModel () { }
private String objectId = String.Empty;
public String ObjectId {
get { return objectId ; }
set {
objectId = value;
}
}
private String imagePath = String.Empty;
public String ImagePath {
get { return imagePath; }
set {
imagePath = value;
OnPropertyChanged();
}
}
public async void OnBackButtonPressed() {
//await Shell.Current.GoToAsync("..");
await Shell.Current.GoToAsync($"..?ObjectId={ObjectId}");
}
В приведенной выше функции «OnBackButtonPressed» приложение создает исключение для любого метода.
В первом случае исключением является следующее:
System.ArgumentException: 'Ambiguous routes matched for: //D_FAULT_TabBar9/D_FAULT_Tab6/UserHomePage/ClientExercisePage matches found: //D_FAULT_TabBar9/D_FAULT_Tab6/UserHomePage/ClientExercisePage,//D_FAULT_TabBar9/D_FAULT_Tab6/UserHomePage/ClientExercisePage. Parameter name: uri'
И во втором случае это так (они практически идентичны. Во втором есть дополнительно»? ObjectId=ff2dcfd1eecf7877″ перед «совпадение не найдено»):
System.ArgumentException: 'Ambiguous routes matched for: //D_FAULT_TabBar11/D_FAULT_Tab6/HomePage/ObjectPage?ObjectId=ff2dcfd1eecf7877 matches found: //D_FAULT_TabBar11/D_FAULT_Tab6/HomePage/ObjectPage,//D_FAULT_TabBar11/D_FAULT_Tab6/HomePage/ObjectPage. Parameter name: uri'
Комментарии:
1. является
ObjectId
ли значение нулевым? также вы могли бы попробоватьawait Shell.Current.GoToAsync("..");
2. Пожалуйста, предоставьте более подходящий код .
3. @FabriBertani, да, я узнал, что
ObjectId
это было пусто. Теперь я исправил проблему, но она выдает мне ту же ошибку. И я также обновил сообщение и добавил соответствующий код
Ответ №1:
Из Xamarin.Оболочка передает данные, которые вы можете использовать await Shell.Current.GoToAsync($"elephantdetails?name={elephantName}");
для перехода к другому с параметром.
Во-первых, я создаю две страницы контента, одна из которых является домашней страницей, с CollectionView для отображения данных списка. Другая страница-Objectdetailpage, для отображения подробной информации.
<CollectionView
x:Name="collectionview1"
ItemsSource="{Binding objectList}"
SelectedItem="{Binding selecteditem}"
SelectionMode="Single">
<CollectionView.ItemTemplate>
<DataTemplate>
<StackLayout Orientation="Horizontal">
<Label Text="{Binding objectId}" />
<Label Text="{Binding name}" />
</StackLayout>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
public class HomePageViewModel:ViewModelBase
{
public ObservableCollection<MyObject> objectList { get; set; }
private MyObject _selecteditem;
public MyObject selecteditem
{
get { return _selecteditem; }
set
{
_selecteditem = value;
RaisePropertyChanged("selecteditem");
if(_selecteditem!=null)
{
Shell.Current.GoToAsync($"objectdetailpage?objectId={selecteditem.objectId}");
}
}
}
public ICommand ObjectTap { get; set; }
public HomePageViewModel()
{
objectList = new ObservableCollection<MyObject>();
ObjectTap = new Command(gotomethod);
for (int i=0;i<10; i )
{
MyObject myobject = new MyObject() { objectId = i, name = "object " i };
objectList.Add(myobject);
}
}
}
Примечание: необходимо реализовать INotifyPropertyChanged
уведомление об изменении выбранных данных.
public class MyObject
{
public int objectId { get; set; }
public string name { get; set; }
}
public class ViewModelBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public void RaisePropertyChanged(string propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
}
Переход к подробной странице. IQueryAttributable
Интерфейс указывает, что реализующий класс должен реализовать ApplyQueryAttributes
метод. Этот метод имеет аргумент запроса типа IDictionary<string, string>
, который содержит любые данные, передаваемые во время навигации.
<StackLayout>
<Label Text="{Binding myobject.objectId}" />
<Label Text="{Binding myobject.name}" />
</StackLayout>
public partial class ObjectDetailPage : ContentPage
{
public ObjectDetailPage()
{
InitializeComponent();
this.BindingContext = new objectviewmodel();
}
}
public class objectviewmodel : IQueryAttributable, INotifyPropertyChanged
{
private MyObject _myobject;
public MyObject myobject
{
get { return _myobject; }
set
{
_myobject = value;
OnPropertyChanged("myobject");
}
}
public void ApplyQueryAttributes(IDictionary<string, string> query)
{
string objectId = HttpUtility.UrlDecode(query["objectId"]);
LoadObject(objectId);
}
private void LoadObject(string objectId)
{
if(objectId!=null)
{
myobject = (new HomePageViewModel()).objectList.FirstOrDefault(a => a.objectId ==int.Parse(objectId));
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
Если вы хотите вернуться, нажав кнопку «Назад», вам не нужно добавлять какой-либо код, просто нажмите кнопку «Назад», он запустит ApplyQueryAttributes
метод для получения параметра.
Чтобы вы могли удалить OnBackButtonPressed
, просто нажмите кнопку «Назад», чтобы перейти к «Назад».
Комментарии:
1. Мне кажется, я понимаю, в чем дело, но я не знаю, почему это происходит. В основном кнопки «Назад» (как на панели навигации, так и внизу, которые присутствуют по умолчанию в системе) работают только на странице, следующей за домашней страницей. После этого, если со второй страницы вы перейдете на другие страницы, этот пункт больше не будет работать. Я прилагаю видео-пример, показывающий проблему. Кнопка «Опубликовать упражнение» при нажатии переходит на новую страницу. Затем, когда я пытаюсь вернуться, это не работает. Вот ссылка: streamable.com/w3asj3
2. Я нашел, в чем была проблема, и не могу поверить, что это было так просто. Весь код, который я написал, был правильным, мне нужно было только удалить некоторые дублированные маршруты в
AppShell.xaml.cs
файле… У меня нет слов 😀