将数据传递给片段视图模型 mvvmcross
Passing data to fragment viewmodel mvvmcross
所以我有一个 activity,它有一个包含 2 个片段的标签页。
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"]);
}
}
到目前为止,None 个已经成功。任何想法我做错了什么?我是否必须使用 MvvmCross 5 的导航服务才能使用 InitFromBundle 和 SaveStateToBundle。
InitFromBundle 每次显示我的片段时都会调用它,但是 SaveStateToBundle 来自 RecipeDetailViewModel 永远不会得到打电话。
为此,您可以利用 MvxViewPagerFragmentPresentationAttribute 以便 Presenter
负责显示片段,而您只需显示传递给 Recipe
的 ViewModel参数和其他任何参数一样,但目前有一些小错误。
然而,解决此问题的一种方法是在 RecipeDetailViewModel
属性中包含您想在 ViewPager
中包含的片段视图模型,然后将它们加载到 Initialize
中您可以从 RecipeDetailActivity
:
中引用它们
使用 Mvx 5,您可以使用新的 Navigation 来显示 ViewModel。如果从 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 中,您只需缓存菜谱,加载 children 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)
的其他构造函数,这样您就可以传递之前加载的 ViewModel:
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()
方法中初始化 children ViewModel。
总结一下,如果您想从 children 更改 Recipe
的值,一种简单的方法是使用 Recipe
初始化单例,然后您只需注入构造函数中的单例,因此您始终可以引用相同的 Recipe,而不必将 Recipe object 来回传递给那些 ViewModel 并合并每个 ViewModel 所做的更改。 MvvmCross: Accessing models by reference from everywhere
中的更多信息
高
所以我有一个 activity,它有一个包含 2 个片段的标签页。
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"]);
}
}
到目前为止,None 个已经成功。任何想法我做错了什么?我是否必须使用 MvvmCross 5 的导航服务才能使用 InitFromBundle 和 SaveStateToBundle。
InitFromBundle 每次显示我的片段时都会调用它,但是 SaveStateToBundle 来自 RecipeDetailViewModel 永远不会得到打电话。
为此,您可以利用 MvxViewPagerFragmentPresentationAttribute 以便 Presenter
负责显示片段,而您只需显示传递给 Recipe
的 ViewModel参数和其他任何参数一样,但目前有一些小错误。
然而,解决此问题的一种方法是在 RecipeDetailViewModel
属性中包含您想在 ViewPager
中包含的片段视图模型,然后将它们加载到 Initialize
中您可以从 RecipeDetailActivity
:
使用 Mvx 5,您可以使用新的 Navigation 来显示 ViewModel。如果从 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 中,您只需缓存菜谱,加载 children 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)
的其他构造函数,这样您就可以传递之前加载的 ViewModel:
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()
方法中初始化 children ViewModel。
总结一下,如果您想从 children 更改 Recipe
的值,一种简单的方法是使用 Recipe
初始化单例,然后您只需注入构造函数中的单例,因此您始终可以引用相同的 Recipe,而不必将 Recipe object 来回传递给那些 ViewModel 并合并每个 ViewModel 所做的更改。 MvvmCross: Accessing models by reference from everywhere
高