Dom*_*ski 5 mvvm xamarin.android mvvmcross xamarin
假设我们有MvvmCross 6.0.1本机应用程序,其中一个Android Activity包含了James MontemagnoBottomNavigationView在本博文中实现的功能,但没有导航和替换片段。
我想做的是将BottomNavigationView项目绑定到ViewModel中的MvxCommands(或MvxAsyncCommands),以便在多个ViewModels之间导航。
我应该采用哪种架构来实现这一目标?我的方法是正确的还是针对MVVM模式和MvvmCross可能性做些什么?
可以在github上找到带有几个附加功能的完整示例。
目前,我(用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);
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
底部导航元素是:
<?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>
Run Code Online (Sandbox Code Playgroud)
视图模型中的命令只是:
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>());
Run Code Online (Sandbox Code Playgroud)
小智 0
您可以为 BottomNavigationView 创建目标绑定并处理 MainViewModel 中的导航,而不是使用 Fluent Binding。在 XML 中使用 Swiss 绑定。
目标绑定类:
public class MvxBottomNavigationItemChangedBinding : MvxAndroidTargetBinding
{
readonly BottomNavigationView _bottomNav;
IMvxCommand _command;
public override MvxBindingMode DefaultMode => MvxBindingMode.TwoWay;
public override Type TargetType => typeof(MvxCommand);
public MvxBottomNavigationItemChangedBinding(BottomNavigationView bottomNav) : base(bottomNav)
{
_bottomNav = bottomNav;
_bottomNav.NavigationItemSelected += OnNavigationItemSelected;
}
public override void SetValue(object value)
{
_command = (IMvxCommand)value;
}
protected override void SetValueImpl(object target, object value)
{
}
void OnNavigationItemSelected(object sender, BottomNavigationView.NavigationItemSelectedEventArgs e)
{
if (_command != null)
_command.Execute(e.Item.TitleCondensedFormatted.ToString());
}
protected override void Dispose(bool isDisposing)
{
if (isDisposing)
_bottomNav.NavigationItemSelected -= OnNavigationItemSelected;
base.Dispose(isDisposing);
}
}
Run Code Online (Sandbox Code Playgroud)
安装程序.cs:
protected override void FillTargetFactories(IMvxTargetBindingFactoryRegistry registry)
{
MvxAppCompatSetupHelper.FillTargetFactories(registry);
base.FillTargetFactories(registry);
registry.RegisterCustomBindingFactory<BottomNavigationView>("BottomNavigationSelectedBindingKey",
view => new MvxBottomNavigationItemChangedBinding(view));
}
Run Code Online (Sandbox Code Playgroud)
底部导航视图 XML :
请注意,我们在Setup.cs中添加的目标绑定键在绑定时使用。
<com.google.android.material.bottomnavigation.BottomNavigationView
android:id="@+id/navigation"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/white"
app:labelVisibilityMode="labeled"
app:menu="@menu/bottom_nav_menu"
app:elevation="10dp"
local:MvxBind="BottomNavigationSelectedBindingKey BottomNavigationItemSelectedCommand"/>
Run Code Online (Sandbox Code Playgroud)
主视图模型:
public class MainViewModel : BaseViewModel
{
public IMvxCommand<string> BottomNavigationItemSelectedCommand { get; private set; }
List<TabViewModel> _tabs;
public List<TabViewModel> Tabs
{
get => _tabs;
set => SetProperty(ref _tabs, value);
}
public MainViewModel(IMvxNavigationService navigationService) : base(navigationService)
{
//these are for android - start
BottomNavigationItemSelectedCommand = new MvxCommand<string>(BottomNavigationItemSelected);
var tabs = new List<TabViewModel>
{
Mvx.IoCProvider.IoCConstruct<FirstViewModel>(),
Mvx.IoCProvider.IoCConstruct<SecondViewModel>(),
Mvx.IoCProvider.IoCConstruct<ThirdViewModel>()
};
Tabs = tabs;
//end
}
// Android-only, not used on iOS
private void BottomNavigationItemSelected(string tabId)
{
if (tabId == null)
{
return;
}
foreach (var item in Tabs)
{
if (tabId == item.TabId)
{
_navigationService.Navigate(item);
break;
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
选项卡视图模型:
public class TabViewModel : BaseViewModel
{
public string TabName { get; protected set; }
public string TabId { get; protected set; }
public TabViewModel(IMvxNavigationService navigationService) : base(navigationService)
{
}
}
Run Code Online (Sandbox Code Playgroud)
底部导航元素:
添加“ android:titleCondensed ”,它将用作 Id。
<?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"
android:titleCondensed ="tab_first"
app:showAsAction="ifRoom" />
<item
android:id="@+id/menu_list"
android:enabled="true"
android:icon="@drawable/ic_list"
android:title="@string/tab2_title"
android:titleCondensed ="tab_second"
app:showAsAction="ifRoom" />
<item
android:id="@+id/menu_settings"
android:enabled="true"
android:icon="@drawable/ic_settings"
android:title="@string/tab3_title"
android:titleCondensed ="tab_third"
app:showAsAction="ifRoom" />
</menu>
Run Code Online (Sandbox Code Playgroud)
视图模型示例:
public class FirstViewModel : TabViewModel
{
public FirstViewModel(IMvxNavigationService navigationService) : base(navigationService)
{
TabId = "tab_first";
}
}
public class SecondViewModel : TabViewModel
{
public SecondViewModel(IMvxNavigationService navigationService) : base(navigationService)
{
TabId = "tab_second";
}
}
Run Code Online (Sandbox Code Playgroud)
希望这对以后进入这个领域的其他人有所帮助!:)
| 归档时间: |
|
| 查看次数: |
684 次 |
| 最近记录: |