首页 > 解决方案 > 使用自定义导航服务,如何将参数传递给下一个视图模型?

问题描述

我正在加快 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 需要一个参数。我试过了,它在日志中没有任何错误。文本中没有关于此方法的任何内容来解释如何使用它。

为此,我可能必须在“捕捉”视图模型中做一些事情。有人可以帮我吗?

标签: c#xamarin.forms

解决方案


首先,您必须从 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)
    {
    }
}

推荐阅读