You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 08:01:19