Xamarin 形成 4 shell 导航复杂参数

Edu*_*ier 3 xamarin.forms xamarin.forms.shell

我正在将带有 Prism 的 xamarin 表单 3.x 应用程序迁移到带有 shell 导航的表单 4。

我是否必须创建我的自定义解决方案来将复杂参数传递到新页面,或者 Xamarin 有一些内置功能可以接收字符串参数以外的内容?

谢谢。

小智 6

我已经运行了一些似乎有效的测试。我对 Xamarin 比较陌生,因此建议谨慎行事,并欢迎针对我可能忽略的任何潜在问题提供任何反馈。

我编写了一个 Shell 扩展来接受数据对象参数“navigationData”,如下所示:-

await Shell.Current.GoToAsync(state, navigationData, animate);
Run Code Online (Sandbox Code Playgroud)

扩展名...

namespace Xamarin.Forms
{
    public static class ShellExtensions
    {
        public static async Task GoToAsync(this Shell shell, ShellNavigationState state, object navigationData, bool animate=false)
        {
            shell.Navigated += async (sender, e) =>
            {
                if ((Shell.Current?.CurrentItem?.CurrentItem as IShellSectionController)?.PresentedPage is MyContentPage
                    p) await p.InitializeAsync(navigationData).ConfigureAwait(false);
            };
            await shell.GoToAsync(state, animate);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

如上图所示,扩展名:-

  1. 挂钩到 Shell 的“导航”事件,
  2. 检索“当前视图(页面)”作为“MyContentPage”,即子类 ContentPage,
  3. 在传入 navigationData 参数的视图上调用 InitializeAsync 方法
  4. 然后,视图在绑定上下文(视图模型)上调用 InitializeAsync 方法,将 navigationData 参数传递到 viewModel。

在上面的扩展方法中,“MyContentPage”是 ContentPage 的自定义抽象子类,具有一个 InitializeAsync(navigationData) 方法,该方法仅在 viewModel(视图的绑定上下文)上调用类似的方法。类似地,ViewModels 是具有虚拟InitializeAsync(navigationData) 的自定义ViewModelBase 类的子类。这可以在 viewModel 中用所需的导航数据实现和处理来覆盖。

视图、视图模型和相关基类的简化示例如下所示

using System.Threading.Tasks;
using MyXamarinApp.ViewModels;
using Xamarin.Forms;

namespace MyXamarinApp.Views
{
    public ItemDetailPage : MyContent<ItemDetailViewModel>{}

    public ItemPage : MyContentPage<ItemViewModel>{}

    public abstract class MyContentPage<T> : MyContentPage where T : ViewModelBase
    {
        protected T Vm;

        protected override ViewModelBase VmBase => Vm as ViewModelBase;

        protected MyContentPage()
        {
            BindingContext = Vm = ViewModelLocator.Resolve<T>();
        }

        private Comand _showDetailCommand;
        public Command ShowDetailCommand
        {
            get { return _showDetailCommand ??= new Command(async () => 
                await Shell.Current.GoToAsync("itemDetail", new NavigationDataObject())); }
        }
    }


    public abstract class MyContentPage : ContentPage
    {
        protected abstract ViewModelBase VmBase { get; }

        public virtual async Task InitializeAsync(object navigationData)
        {
            await VmBase.InitializeAsync(navigationData);
        }
    }
}

public class NavigationDataObject
{
    'Properties' etc.
}

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq.Expressions;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Threading.Tasks;

namespace MyXamarinApp.ViewModels
{
    public ItemViewModel : ViewModelBase{}

    public ItemDetailViewModel : ViewModelBase
    {
        private NavigationDataObject _navData;
        public override async Task InitializeAsync(object navigationData)
        {
            if (navigationData is NavigationDataObject navData)
            {
                _navData = navData;
            }
            await base.InitializeAsync(navigationData);
        }
    }

    public abstract class ViewModelBase
    {

        public virtual Task InitializeAsync(object navigationData)
        {
            return Task.FromResult(false);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)


Bru*_*iro 5

据我所知,并且在阅读文档时,唯一的示例是在导航时传递简单数据,例如字符串。

但是,我能够找到一个问题(和拉取请求),用于传递对象/模型,用于下一个版本(我认为这就是您所指的情况)。

你可以在这里跟踪它。


Chr*_*s A 5

您始终可以将模型序列化为 JSON 字符串并在另一端取消序列化它?

    async void Handle_ItemTapped(object sender, ItemTappedEventArgs e)
    {
        if (e.Item == null)
            return;

        DailyPnL PnLClicked = (DailyPnL)e.Item;
        string jason = await Task.Run(() => JsonConvert.SerializeObject(PnLClicked));

        await Shell.Current.GoToAsync($"viewdailypnl?pnlmodel={jason}");

        //Deselect Item
        ((ListView)sender).SelectedItem = null;
    }
Run Code Online (Sandbox Code Playgroud)

然后在你的代码后面:

    public string pnlmodel
    {
        set
        {
            string derulo = Uri.UnescapeDataString(value);
            viewModel.PnL =  Task.Run(() => JsonConvert.DeserializeObject<DailyPnL>(derulo)).Result;

        }
    }
Run Code Online (Sandbox Code Playgroud)

  • 这对我有用,我只需在将 json 字符串附加到 uri 之前对其进行转义:Uri.EscapeDataString(JsonConvert.SerializeObject(PnLClicked))。 (2认同)