TabLayout中的片段不绑定到viewmodel
问题描述:
我一直在为此挣扎2天,而且现在我很困难。由于某些原因,片段的绑定根本无法启动。页面显示正确,并且选项卡可以正常工作。我可以从选项卡1滑动到2,反之亦然。 TextView应该显示来自视图模型的一些文本。当我调试这两个片段的构造函数时,viewmodel被执行,但是LoginNotificationViewModel(LoginDescription和LastLoginRequestReceivedOn)的属性永远不会触发。TabLayout中的片段不绑定到viewmodel
我有一个持有TabLayout,你可以看到下面一个观点:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:local="http://schemas.android.com/apk/res-auto"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<include
layout="@layout/header" />
<LinearLayout
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:id="@+id/main_content"
android:layout_below="@id/header">
<android.support.design.widget.TabLayout
android:id="@+id/sliding_tabs"
android:layout_width="match_parent"
android:layout_height="wrap_content"
local:tabMode="fixed" />
<android.support.v4.view.ViewPager
android:id="@+id/viewpager"
android:layout_width="match_parent"
android:layout_height="0px"
android:layout_weight="1"
android:background="@android:color/white" />
</LinearLayout>
</RelativeLayout>
的TabView的代码:
using Android.App;
using Android.OS;
using Android.Runtime;
using Android.Support.Design.Widget;
using Android.Support.V4.View;
using Android.Support.V7.Widget;
using Android.Views;
using MvvmCross.Droid.Support.V4;
using Notifier.Adapters;
using Notifier.Android.Fragments;
using Notifier.Classes;
using Notifier.ViewModels;
using System;
using static MvvmCross.Droid.Support.V4.MvxCachingFragmentStatePagerAdapter;
namespace Notifier.Android.Views
{
[Activity(Label = "HomeNotification", Theme = "@style/Theme.NatuurNetwerk.Main", NoHistory = true)]
public class HomeNotificationView : MvxFragmentActivity<HomeNotificationViewModel>
{
private HomeNotificationViewModel _HomeNotificationViewModel;
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
_HomeNotificationViewModel = this.ViewModel;
SetContentView(Resource.Layout.HomeNotificationView);
var fragments = new FragmentInfo[]
{
new FragmentInfo("Login", typeof(LoginNotificationFragment), typeof(LoginNotificationViewModel)),
new FragmentInfo("Tekst", typeof(TextNotificationFragment), typeof(TextNotificationViewModel)),
};
var viewPager = FindViewById<ViewPager>(Resource.Id.viewpager);
viewPager.Adapter = new TabsFragmentPagerAdapter(this, SupportFragmentManager, fragments);
// Give the TabLayout to the ViewPager
var tabLayout = FindViewById<TabLayout>(Resource.Id.sliding_tabs);
tabLayout.SetupWithViewPager(viewPager, true);
}
public override bool OnCreateOptionsMenu(IMenu menu)
{
SetContentView(Resource.Layout.HomeNotificationView);
menu.Add(Menu.None, (int)Parameters.NotificationMenuItems.ResetPincode, 0, Resource.String.menuResetPincode);
menu.Add(Menu.None, (int)Parameters.NotificationMenuItems.AddApplication, 0, Resource.String.menuAddApplication);
menu.Add(Menu.None, (int)Parameters.NotificationMenuItems.RemoveApplication, 0, Resource.String.menuRemoveApplication);
return base.OnCreateOptionsMenu(menu);
}
public override bool OnOptionsItemSelected(IMenuItem item)
{
Parameters.NotificationMenuItems menuItemSelected = item.ItemId.GetEnum<Parameters.NotificationMenuItems>();
switch (menuItemSelected)
{
case Parameters.NotificationMenuItems.ResetPincode:
_HomeNotificationViewModel.ResetPincode();
break;
case Parameters.NotificationMenuItems.AddApplication:
break;
case Parameters.NotificationMenuItems.RemoveApplication:
break;
default:
throw new InvalidOperationException(string.Format("Notifier: Invalid menu {0}", menuItemSelected.ToString()));
}
return base.OnOptionsItemSelected(item);
}
protected override void OnResume()
{
base.OnResume();
Toolbar toolbar = FindViewById(Resource.Id.toolbar) as Toolbar;
if (toolbar != null)
{
toolbar.Title = _HomeNotificationViewModel.Title;
toolbar.Subtitle = _HomeNotificationViewModel.SubTitle;
}
}
}
}
..和它的视图模型:
namespace Notifier.ViewModels
{
public class HomeNotificationViewModel : ViewModelBase
{
public override string SubTitle => "Notificatie";
public override void InitView()
{
}
public override void InitData()
{
// TODO: Init Data
}
public override void ApplicationSelected()
{
}
public void ResetPincode()
{
DeviceRegistrationHelper.UpdatePincode(null,() =>
{
DetermineAndStartHomeView();
});
}
}
}
涉及的片段之一:
<?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">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="30dp"
local:MvxBind="Text LoginDescription" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="30dp"
local:MvxBind="Text LastLoginRequestReceivedOn"/>
</LinearLayout>
登录片段代码:
using Android.OS;
using Android.Views;
using Notifier.ViewModels;
namespace Notifier.Android.Fragments
{
public class LoginNotificationFragment : BaseFragment<LoginNotificationViewModel>
{
protected override int LayoutResource => Resource.Layout.LoginNotificationFragment;
public override View OnCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
return inflater.Inflate(Resource.Layout.LoginNotificationFragment, container, false);
}
}
}
..和它的基类:
using MvvmCross.Droid.Support.V4;
using Notifier.Android.Views;
using Notifier.ViewModels;
namespace Notifier.Android.Fragments
{
public abstract class BaseFragment<TViewModel> : MvxFragment<TViewModel>
where TViewModel : ViewModelBase
{
protected abstract int LayoutResource { get; }
}
}
视图模型:
using Notifier.Classes;
using System;
using System.Linq;
namespace Notifier.ViewModels
{
public class LoginNotificationViewModel : ViewModelBase
{
public override string SubTitle => "Inlog notificatie";
public String Status { get; set; }
public override void InitView()
{
}
public override void InitData()
{
// TODO: Init Data
}
public override void ApplicationSelected()
{
}
public string LoginDescription
{
get => Settings.HasNotification
? string.Format("Er is een inlog verzoek ontvangen voor {0}", ApplicationShortName(Settings.Notification.ApplicationId))
: "Geen openstaande inlogverzoeken";
}
/// <summary>
/// Short name for the application
/// </summary>
private string ApplicationShortName(int applicationId)
{
return Applications.Where(app => app.ApplicationID == applicationId).FirstOrDefault()?.ApplicationEntity.ApplicationShortName;
}
public string LastLoginRequestReceivedOn
{
get => string.Format("Laatste inlogverzoek: {0}",
Settings.HasLastNotificationReceivedOn
? string.Empty
: Settings.LastNotificationReceivedOn.ToString("DD-MM-YYYY HH:MM"));
}
}
}
和(部分)的基类:
namespace Notifier.ViewModels
{
/// <summary>
/// Base class for all view models.
/// </summary>
public abstract class ViewModelBase : MvxViewModel
{
private readonly IPlatformEntrance _platformEntrance;
private readonly IPlatformLog _platformLog;
public string Title => "nNotifier©";
public ViewModelBase()
{
_platformEntrance = Mvx.Resolve<IPlatformEntrance>();
_platformLog = Mvx.Resolve<IPlatformLog>();
InitData();
}
public abstract void InitData();
public abstract string SubTitle { get; }
...
}
}
这里的PageAdapter:
using Android.Content;
using Android.Support.V4.App;
using MvvmCross.Droid.Support.V4;
namespace Notifier.Adapters
{
public class TabsFragmentPagerAdapter : MvxCachingFragmentStatePagerAdapter
{
FragmentInfo[] _fragments;
public TabsFragmentPagerAdapter(Context context, FragmentManager fragmentManager, FragmentInfo[] fragments)
: base(context, fragmentManager, fragments)
{
_fragments = fragments;
}
// public override int Count => _fragments.Length;
//public override global::Android.Support.V4.App.Fragment GetItem(int position,
// global::Android.Support.V4.App.Fragment.SavedState fragmentSavedState = null)
//{
// return _fragments[position];
//}
//public override ICharSequence GetPageTitleFormatted(int position)
//{
// return _titles[position];
//}
}
}
答
您需要使用BindingInflate()
,而不是默认的Android吹气,因为它不知道如何处理MvxBind性能。
using MvvmCross.Binding.Droid.BindingContext;
...
public override View OnCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
var ignored = base.OnCreateView(inflater, container, savedInstanceState);
var view = this.BindingInflate(Resource.Layout.MyFragmentLayout, container, false);
return view;
}
啊,我以前在某个地方看过这个评论。我没有在这个想法中找到它,并且从未意识到它是een扩展方法。 当我添加片段时,我得到一个NullReferenceException –
看来我也需要base.OnCreateView,因为它现在起作用了。非常感谢你 –