Используя настраиваемую службу навигации, как передать параметр в следующую модель представления?

Я быстро осваиваю Xamarin. В качестве руководства я использую «Освоение Xamarin.Forms: методы архитектуры приложений для создания многоплатформенных собственных мобильных приложений с Xamarin.Forms 4, 3-е издание». Это заставило меня создать собственный навигационный сервис.

Вот реализация (я пропустил интерфейс для краткости)

namespace wfw_dispenser.Services
{
    public class XamarinFormsNavService : INavService
    {
        readonly IDictionary<Type, Type> _map = new Dictionary<Type, Type>();

        public event PropertyChangedEventHandler CanGoBackChanged;

        public INavigation XamarinFormsNav { get; set; }

        public bool CanGoBack => XamarinFormsNav.NavigationStack?.Any() == true;

        public async Task GoBack()
        {
            if (CanGoBack)
            {
                await XamarinFormsNav.PopAsync(true);
                OnCanGoBackChanged();
            }
        }

        public async Task NavigateTo<TVM>()
            where TVM : BaseViewModel
        {
            await NavigateToView(typeof(TVM));

            if (XamarinFormsNav.NavigationStack.Last().BindingContext is BaseViewModel)
            {
                ((BaseViewModel)XamarinFormsNav.NavigationStack.Last().BindingContext).Init();
            }
        }

        public async Task NavigateTo<TVM, TParameter>(TParameter parameter)
            where TVM : BaseViewModel
        {
            await NavigateToView(typeof(TVM));

            if (XamarinFormsNav.NavigationStack.Last().BindingContext is BaseViewModel<TParameter>)
            {
                ((BaseViewModel<TParameter>)XamarinFormsNav.NavigationStack.Last().BindingContext).Init(parameter);
            }
        }

        public void RemoveLastView()
        {
            if (XamarinFormsNav.NavigationStack.Count< 2)
            {
                return;
            }

            var lastView = XamarinFormsNav.NavigationStack[XamarinFormsNav.NavigationStack.Count - 2];

            XamarinFormsNav.RemovePage(lastView);
        }

        public void ClearBackStack()
        {
            if (XamarinFormsNav.NavigationStack.Count < 2)
            {
                return;
            }

            for (var i = 0; i < XamarinFormsNav.NavigationStack.Count - 1; i++)
            {
                XamarinFormsNav.RemovePage(XamarinFormsNav.NavigationStack[i]);
            }
        }

        public void NavigateToUri(Uri uri)
        {
            if (uri == null)
            {
                throw new ArgumentException("Invalid URI");
            }

            Device.OpenUri(uri);
        }

        async Task NavigateToView(Type viewModelType)
        {
            if (!_map.TryGetValue(viewModelType, out Type viewType))
            {
                throw new ArgumentException("No view found in view mapping for " + viewModelType.FullName + ".");
            }

            // Use reflection to get the View's constructor and create an instance of the View
            var constructor = viewType.GetTypeInfo()
                                      .DeclaredConstructors
                                      .FirstOrDefault(dc => !dc.GetParameters().Any());
            var view = constructor.Invoke(null) as Page;
            var vm = ((App)Application.Current).Kernel.GetService(viewModelType);

            view.BindingContext = vm;
            await XamarinFormsNav.PushAsync(view, true);
        }

        public void RegisterViewMapping(Type viewModel, Type view)
        {
            _map.Add(viewModel, view);
        }

        void OnCanGoBackChanged() => CanGoBackChanged?.Invoke(this, new PropertyChangedEventArgs("CanGoBack"));
    }
}

Мне кажется, что есть NavigateTo, который принимает параметр. Я попробовал, и он никуда не уходит без каких-либо ошибок в журнале. В тексте об этом методе нет ничего, чтобы объяснить, как его использовать.

Вероятно, для этого мне нужно что-то сделать в модели представления «захвата». Кто-нибудь может мне помочь?

См. BaseViewModel<T> - github.com/edsnider/mastering-xamarin.forms-book/blob/…

Jason 18.12.2020 21:27

@ Джейсон, ааа, пропустил это. Итак, я просто реализую этот метод в своем конкретном классе?

Thom 18.12.2020 23:05

Также вы можете написать свою проверку типов короче с сопоставлением с образцом: if (XamarinFormsNav.NavigationStack.Last().BindingContext is BaseViewModel baseVM) { baseVM.Init(); }

Pieterjan 19.12.2020 01:22
Почему в Python есть оператор &quot;pass&quot;?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Коллекции в Laravel более простым способом
Коллекции в Laravel более простым способом
Привет, читатели, сегодня мы узнаем о коллекциях. В Laravel коллекции - это способ манипулировать массивами и играть с массивами данных. Благодаря...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
Массив зависимостей в React
Массив зависимостей в React
Все о массиве Dependency и его связи с useEffect.
0
3
142
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Во-первых, вы должны расширить параметризованную версию BaseViewModel. В вашем случае, поскольку вы передаете PaymentRequest, это будет:

public class CheckoutViewModel : BaseViewModel<PaymentRequest>

Тогда у BaseViewModel<T> есть виртуальный Init метод, который вы можете реализовать

public class BaseViewModel<TParameter> : BaseViewModel
{
    protected BaseViewModel(INavService navService, IAnalyticsService analyticsService)
        : base(navService, analyticsService)
    {
    }

    public override void Init()
    {
        Init(default(TParameter));
    }

    public virtual void Init(TParameter parameter)
    {
    }
}

Другие вопросы по теме