假设我们有MvvmCross 6.0.1本机应用程序,其中一个Android活动包含 BottomNavigationView ,如this blog post by James Montemagno所示,但没有导航和替换片段 .

我想要做的是将 BottomNavigationView 项绑定到ViewModel中的MvxCommands(或MvxAsyncCommands),以便在多个ViewModel之间导航 .

我应该采用什么样的架构来实现这一目标? Is my approach correct or am I doing something against MVVM pattern and MvvmCross possibilities?

完整的工作示例有几个附加功能,可以找到here on github .

animated gif showing current progress

目前我有(搭建MvxScaffolding) .

  • MainContainerActivity 和相应的 MainContainerViewModel - 这里我想存储命令以在视图模型之间导航

  • MainFragment 和相应的 MainViewModel - 这是第一个片段/视图模型

  • SettingsFragment 和相应的 SettingsViewModel - 我想从 MainViewModel 导航到它,反之亦然

  • FavoritesFragment 和相应的 FavoritesViewModel

主要活动如下:

using Android.App;
using Android.OS;
using Android.Views;
using PushNotifTest.Core.ViewModels.Main;
using Microsoft.AppCenter;
using Microsoft.AppCenter.Analytics;
using Microsoft.AppCenter.Crashes;
using Microsoft.AppCenter.Push;
using Android.Graphics.Drawables;
using Android.Support.Design.Widget;
using MvvmCross.Binding.BindingContext;
using System;
using System.Windows.Input;

namespace PushNotifTest.Droid.Views.Main
{
    [Activity(
        Theme = "@style/AppTheme",
        WindowSoftInputMode = SoftInput.AdjustResize | SoftInput.StateHidden)]
    public class MainContainerActivity : BaseActivity<MainContainerViewModel>
    {
        protected override int ActivityLayoutId => Resource.Layout.activity_main_container;

        BottomNavigationView bottomNavigation;

        public ICommand GoToSettingsCommand { get; set; }
        public ICommand GoToFavoritesCommand { get; set; }
        public ICommand GoToHomeCommand { get; set; }

        protected override void OnCreate(Bundle bundle)
        {
            base.OnCreate();
            AddBottomNavigation();
        }

        private void AddBottomNavigation()
        {
            bottomNavigation = (BottomNavigationView)FindViewById(Resource.Id.bottom_navigation);
            if (bottomNavigation != null)
            {
                bottomNavigation.NavigationItemSelected += BottomNavigation_NavigationItemSelected;
                // trying to bind command to view model property
                var set = this.CreateBindingSet<MainContainerActivity, MainContainerViewModel>();
                set.Bind(this).For(v => v.GoToSettingsCommand).To(vm => vm.NavigateToSettingsCommand);
                set.Bind(this).For(v => v.GoToHomeCommand).To(vm => vm.NavigateToHomeCommand);
                set.Bind(this).For(v => v.GoToFavoritesCommand).To(vm => vm.NavigateToFavoritesCommand);
                set.Apply();
            }
            else
            {
                System.Diagnostics.Debug.WriteLine("Bottom navigation menu is null");
            }
        }

        private void BottomNavigation_NavigationItemSelected(object sender, BottomNavigationView.NavigationItemSelectedEventArgs e)
        {
            try
            {
                System.Diagnostics.Debug.WriteLine($"Bottom navigation menu is selected: {e.Item.ItemId}");

                if (e.Item.ItemId == Resource.Id.menu_settings)
                    if (GoToSettingsCommand != null && GoToSettingsCommand.CanExecute(null))
                        GoToSettingsCommand.Execute(null);
                if (e.Item.ItemId == Resource.Id.menu_list)
                    if (GoToFavoritesCommand != null && GoToFavoritesCommand.CanExecute(null))
                        GoToFavoritesCommand.Execute(null);
                if (e.Item.ItemId == Resource.Id.menu_home)
                    if (GoToHomeCommand != null && GoToHomeCommand.CanExecute(null))
                        GoToHomeCommand.Execute(null);
            }
            catch (Exception exception)
            {
                System.Diagnostics.Debug.WriteLine($"Exception: {exception.Message}");
                Crashes.TrackError(exception);
            }
        }
    }
}

底部导航元素是:

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">
  <item
      android:id="@+id/menu_home"
      android:enabled="true"
      android:icon="@drawable/ic_history"
      android:title="@string/tab1_title"
      app:showAsAction="ifRoom" />

  <item
      android:id="@+id/menu_list"
      android:enabled="true"
      android:icon="@drawable/ic_list"
      android:title="@string/tab2_title"
      app:showAsAction="ifRoom" />

  <item
      android:id="@+id/menu_settings"
      android:enabled="true"
      android:icon="@drawable/ic_settings"
      android:title="@string/tab3_title"
      app:showAsAction="ifRoom" />
</menu>

视图模型中的命令只是:

public IMvxAsyncCommand NavigateToSettingsCommand => new MvxAsyncCommand(async () => await _navigationService.Navigate<SettingsViewModel>());
public IMvxAsyncCommand NavigateToFavoritesCommand => new MvxAsyncCommand(async () => await _navigationService.Navigate<FavoritesViewModel>());
public IMvxAsyncCommand NavigateToHomeCommand => new MvxAsyncCommand(async () => await _navigationService.Navigate<MainViewModel>());