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

#c# #xamarin.forms

#c# #xamarin.forms

Вопрос:

Я набираю скорость в Xamarin. Я использую «Освоение Xamarin.Формы: методы архитектуры приложений для создания многоплатформенных собственных мобильных приложений с помощью Xamarin.Формы 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, который принимает параметр. Я попробовал это, и это вроде как никуда не уходит без каких-либо ошибок в журнале. В тексте об этом методе нет ничего, объясняющего, как его использовать.

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

Комментарии:

1. смотрите BaseViewModel<T> github.com/edsnider/mastering-xamarin.forms-book/blob /…

2. @Jason, Ах, пропустил это. Итак, я просто реализую этот метод в своем конкретном классе?

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

Ответ №1:

Во-первых, вы должны перейти от параметризованной версии BaseViewModel. В вашем случае, поскольку вы передаете в a 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)
    {
    }
}