Xamarin MvvmCross 5下Android嵌套碎片实现求助:求可用示例
我完全理解在MvvmCross 5的Xamarin.Android项目里实现嵌套Fragment有多闹心——官方确实没给出太多现成的示例。下面我给你一份完整可运行的核心实现代码,涵盖ViewModel、父Fragment、子Fragment以及绑定的关键细节:
嵌套Fragment实现示例(MvvmCross 5 + Xamarin.Android)
1. ViewModel层实现
首先定义父ViewModel和子ViewModel,父ViewModel负责管理子ViewModel的切换逻辑:
using MvvmCross.Core.ViewModels; using MvvmCross.Commands; public class ParentNestedViewModel : MvxViewModel { private IMvxViewModel _currentChildViewModel; public IMvxViewModel CurrentChildViewModel { get => _currentChildViewModel; set => SetProperty(ref _currentChildViewModel, value); } // 切换子Fragment的命令 public ICommand SwitchToFirstChildCommand => new MvxCommand(() => CurrentChildViewModel = new ChildFirstViewModel()); public ICommand SwitchToSecondChildCommand => new MvxCommand(() => CurrentChildViewModel = new ChildSecondViewModel()); public override void Prepare() { base.Prepare(); // 默认加载第一个子Fragment CurrentChildViewModel = new ChildFirstViewModel(); } } public class ChildFirstViewModel : MvxViewModel { private string _message = "我是第一个子Fragment的内容"; public string Message { get => _message; set => SetProperty(ref _message, value); } } public class ChildSecondViewModel : MvxViewModel { private string _message = "我是第二个子Fragment的内容"; public string Message { get => _message; set => SetProperty(ref _message, value); } }
2. 父Fragment(承载子Fragment的容器)
父Fragment继承MvxFragment,布局中包含子Fragment的容器,并通过监听ViewModel属性变化来切换子Fragment:
using Android.App; using Android.OS; using Android.Views; using MvvmCross.Droid.Support.V4; using MvvmCross.Core.ViewModels; using MvvmCross.Droid.Views; [MvxFragmentPresentation(typeof(MainViewModel), Resource.Id.content_frame, true)] public class ParentNestedFragment : MvxFragment<ParentNestedViewModel> { public override View OnCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { base.OnCreateView(inflater, container, savedInstanceState); var view = this.BindingInflate(Resource.Layout.fragment_parent_nested, container, false); // 监听子ViewModel变化,自动切换子Fragment ViewModel.PropertyChanged += (sender, args) => { if (args.PropertyName == nameof(ViewModel.CurrentChildViewModel)) { ReplaceChildFragment(ViewModel.CurrentChildViewModel); } }; return view; } private void ReplaceChildFragment(IMvxViewModel childViewModel) { // 通过MvvmCross的视图查找器获取对应的子Fragment var childFragment = Mvx.IoCProvider.Resolve<IMvxAndroidViewModelViewFinder>().FindView(childViewModel) as Fragment; if (childFragment == null) return; // 注意:嵌套Fragment必须用ChildFragmentManager,不能用FragmentManager var transaction = ChildFragmentManager.BeginTransaction(); transaction.Replace(Resource.Id.child_fragment_container, childFragment); transaction.Commit(); } }
对应的父Fragment布局fragment_parent_nested.axml:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:local="http://schemas.android.com/apk/res-auto" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent"> <LinearLayout android:orientation="horizontal" android:layout_width="match_parent" android:layout_height="wrap_content" android:padding="16dp"> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="切换到子Fragment1" local:MvxBind="Click SwitchToFirstChildCommand"/> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="切换到子Fragment2" android:layout_marginLeft="16dp" local:MvxBind="Click SwitchToSecondChildCommand"/> </LinearLayout> <!-- 子Fragment的容器FrameLayout --> <FrameLayout android:id="@+id/child_fragment_container" android:layout_width="match_parent" android:layout_height="match_parent"/> </LinearLayout>
3. 子Fragment实现
两个子Fragment分别绑定对应的ViewModel,展示各自的内容:
using Android.Views; using MvvmCross.Droid.Support.V4; public class ChildFirstFragment : MvxFragment<ChildFirstViewModel> { public override View OnCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { base.OnCreateView(inflater, container, savedInstanceState); return this.BindingInflate(Resource.Layout.fragment_child_first, container, false); } } public class ChildSecondFragment : MvxFragment<ChildSecondViewModel> { public override View OnCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { base.OnCreateView(inflater, container, savedInstanceState); return this.BindingInflate(Resource.Layout.fragment_child_second, container, false); } }
子Fragment布局fragment_child_first.axml:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:local="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="match_parent" android:gravity="center"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:textSize="20sp" local:MvxBind="Text Message"/> </LinearLayout>
fragment_child_second.axml与上面结构一致,仅绑定的ViewModel不同。
4. 关键注意事项
- 必须用
ChildFragmentManager:父Fragment切换子Fragment时,一定要使用ChildFragmentManager而非FragmentManager,否则会引发生命周期异常,这是嵌套Fragment的核心要点。 - 属性变更通知:父ViewModel的
CurrentChildViewModel属性必须触发PropertyChanged事件,这样Fragment才能感知到变化并执行切换逻辑。 - 自动注册:MvvmCross 5会自动扫描并注册ViewModel与Fragment的对应关系,无需手动注册(如果有自定义命名规则则需额外配置)。
内容的提问来源于stack exchange,提问作者SC_CSharp
相关产品推荐
相关产品推荐

