3

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

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

谢谢。

4

4 回答 4

5

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

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

你可以在这里追踪它。

于 2019-08-19T11:10:13.687 回答
4

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

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

await Shell.Current.GoToAsync(state, navigationData, animate);

扩展...

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);
        }
    }
}

如上图所示:-

  1. 挂钩到 Shell 'Navigated' 事件,
  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);
        }
    }
}
于 2020-05-18T15:53:48.580 回答
4

您总是可以将模型序列化为 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;
    }

然后在你的代码后面:

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

        }
    }
于 2019-11-17T19:27:01.890 回答
1

有一个名为Xamarin.Zero https://github.com/markjackmilian/Xam.Zero的框架 ,它允许您使用 shell,同时为您提供方便的 ViewModel 到 ViewModel 导航,IOC。

于 2020-01-26T18:00:21.240 回答