向片段视图模型传递数据的方法(MVVMCross)

6

我有一个带有两个片段的选项卡页面的活动。

  public class RecipeDetailActivity : BaseFragmentActivity<RecipeDetailViewModel>
    {
        protected override void OnCreate(Bundle savedInstanceState)
        {
            base.OnCreate(savedInstanceState);

            SetContentView(Resource.Layout.RecipeDetailView);

            AttachActionBar();
            SupportActionBar.SetDisplayHomeAsUpEnabled(true);
            SupportActionBar.Title = "Recipe details";

            var viewPager = FindViewById<ViewPager>(Resource.Id.main_view_pager);

            if (viewPager != null)
            {
                var fragments = new List<MvxViewPagerFragmentInfo>();
                fragments.Add(
                    new MvxViewPagerFragmentInfo("Ingrediente", typeof(RecipeFlavoursFragment), typeof(RecipeFlavoursViewModel)));
                fragments.Add(
                    new MvxViewPagerFragmentInfo("Flavours", typeof(RecipeIngridientsFragment), typeof(RecipeIngridientsViewModel)));

                viewPager.Adapter = new MvxFragmentPagerAdapter(this, SupportFragmentManager, fragments);


                viewPager.Adapter = new MvxFragmentPagerAdapter(this, SupportFragmentManager, fragments);
                var tabLayout = FindViewById<TabLayout>(Resource.Id.main_tablayout);
                tabLayout.SetupWithViewPager(viewPager);
            }
        }
    }

我使用以下代码显示此页面。
   private void SelectRecipe(RecipeModel recipe)
   {
            var recipeJson = JsonConvert.SerializeObject(recipe);

            ShowViewModel<RecipeDetailViewModel>(new { recipe = recipeJson });
   }

现在我想传递一些数据给子视图模型。 RecipeFlavoursViewModel RecipeIngridientsViewModel 到目前为止,我尝试过: 使用parameterValueObject
        fragments.Add(
            new MvxViewPagerFragmentInfo("Ingrediente", typeof(RecipeFlavoursFragment), typeof(RecipeFlavoursViewModel), new { recipe = ViewModel.Recipe }));

使用 IMvxBundle

RecipeDetailViewModel

 protected override void SaveStateToBundle(IMvxBundle bundle)
 {
            bundle.Data["Recipe"] = JsonConvert.SerializeObject(Recipe);

            base.SaveStateToBundle(bundle);
 }

RecipeIngridientsViewModel
protected override void InitFromBundle(IMvxBundle parameters)
        {
            base.InitFromBundle(parameters);

            if (parameters.Data.Count != 0)
            {
                Recipe = JsonConvert.DeserializeObject<RecipeModel>(parameters.Data["recipe"]);
            }
        }

到目前为止,它们都没有起作用。有什么想法我做错了什么吗?我是否必须使用MvvmCross 5的导航服务才能使用InitFromBundle和SaveStateToBundle。

InitFromBundle每次显示我的片段时都会被调用,但RecipeDetailViewModel中的SaveStateToBundle从未被调用。

1个回答

6
为了实现这一点,您可以利用MvxViewPagerFragmentPresentationAttribute,以便Presenter负责显示片段,您只需像其他一样传递Recipe参数并显示ViewModels,但目前存在一些小问题。
然而,解决此问题的一种方法是在RecipeDetailViewModel中拥有与您想在ViewPager中拥有的片段ViewModel相关的属性,并在Initialize中加载它们,然后您可以从您的RecipeDetailActivity引用它们:
使用Mvx 5,您可以使用新的导航来显示ViewModels。如果从RecipeListViewModel打开详细信息,则:
public class RecipeDetailViewModelArgs
{
    public RecipeDetailViewModelArgs(RecipeModel recipe)
    {
        this.Recipe = recipe;
    }

    public RecipeModel Recipe { get; }
}

public class RecipeListViewModel : MvxViewModel
{
    private readonly IMvxNavigationService navigationService;

    public RecipeListViewModel(IMvxNavigationService navigationService)
    {
        this.navigationService = navigationService;
    }

    private async Task SelectRecipe(RecipeModel recipe)
    {
        await this.navigationService.Navigate<RecipeDetailViewModel, RecipeDetailViewModelArgs>(new RecipeDetailViewModelArgs(recipe));
    }
}

然后在您的详细信息ViewModel中,您只需要缓存该食谱,加载子ViewModel(成分和口味),并将该食谱设置为它们:

public class RecipeDetailViewModel : MvxViewModel<RecipeDetailViewModelArgs>
{
    private readonly IMvxViewModelLoader mvxViewModelLoader;
    private readonly IMvxJsonConverter jsonConverter;
    private RecipeModel recipe;

    public RecipeDetailViewModel(IMvxViewModelLoader mvxViewModelLoader, IMvxJsonConverter jsonConverter)
    {
        this.mvxViewModelLoader = mvxViewModelLoader;
        this.jsonConverter = jsonConverter;
    }

    public override void Prepare(RecipeDetailViewModelArgs parameter)
    {
        this.recipe = parameter.Recipe;
    }

    protected override void SaveStateToBundle(IMvxBundle bundle)
    {
        base.SaveStateToBundle(bundle);

        bundle.Data["RecipeKey"] = this.jsonConverter.SerializeObject(this.recipe);
    }

    protected override void ReloadFromBundle(IMvxBundle state)
    {
        base.ReloadFromBundle(state);

        this.recipe = this.jsonConverter.DeserializeObject<RecipeModel>(state.Data["RecipeKey"]);
    }

    public override async Task Initialize()
    {
        await base.Initialize();

        this.InitializeChildrenViewModels();
    }

    public RecipeFlavoursViewModel FlavoursViewModel { get; private set; }

    public RecipeIngridientsViewModel IngredientsViewModel { get; private set; }

    protected virtual void InitializeChildrenViewModels()
    {
        // Load each childre ViewModel and set the recipe
        this.FlavoursViewModel = this.mvxViewModelLoader.LoadViewModel(new MvxViewModelRequest<RecipeFlavoursViewModel>(null, null), null);
        this.FlavoursViewModel.Recipe = this.recipe;

        this.IngredientsViewModel = this.mvxViewModelLoader.LoadViewModel(new MvxViewModelRequest<RecipeIngridientsViewModel>(null, null), null);
        this.FlavoursViewModel.Recipe = this.recipe;
    }
}

当你加载ViewPager时,你可以利用MvxViewPagerFragmentInfo的另一个构造函数 => public MvxViewPagerFragmentInfo (string title, string tag, Type fragmentType, IMvxViewModel viewModel, object parameterValuesObject = null),这样你就可以传递之前已经加载好的ViewModels:

this.viewPager = view.FindViewById<ViewPager>(Resource.Id.viewPagerDetails);
if (viewPager != null)
{
    var fragments = new List<MvxViewPagerFragmentInfo>();
    fragments.Add(new MvxViewPagerFragmentInfo("Ingredients", "RecipeIngridientsViewModelTag", typeof(RecipeIngridientsView), this.ViewModel.IngridientsViewModel));
    fragments.Add(new MvxViewPagerFragmentInfo("Flavours", "RecipeFlavoursViewModelTag", typeof(RecipeFlavoursView), this.ViewModel.FlavoursViewModel));

    this.viewPager.Adapter = new MvxFragmentPagerAdapter(this.Activity, this.ChildFragmentManager, fragments);
}

就是这样。


顺便说一下,如果您不想使用导航或者您没有使用Mvx 5.x,那么您只需要在void Start()方法中初始化子ViewModels。

最后,如果您想要从子ViewModel更改Recipe的值,一个简单的方法是使用一个已经初始化了Recipe的Singleton,然后在构造函数中注入Singleton,这样您就始终拥有对同一个Recipe的引用,而无需将Recipe对象传递给这些ViewModels并合并每个ViewModel所做的更改。更多信息请参见MvvmCross:从任何地方访问模型

希望对您有所帮助。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接