2017-05-25 6 views
-1

Ich habe seit 2 Tagen damit zu kämpfen und bin ganz einfach stecken geblieben. Die Bindung der Fragmente wird aus irgendeinem Grund einfach nicht eintreten. Die Seite wird korrekt angezeigt und die Registerkarten funktionieren einwandfrei. Ich kann von Tab 1 nach 2 wischen und umgekehrt. Die TextView sollte etwas Text aus dem Viewmodel anzeigen. Beim Debuggen werden die Konstruktoren beider Fragment-View-Modelle ausgeführt, aber die Eigenschaften auf dem LoginNotificationViewModel (LoginDescription und LastLoginRequestReceivedOn) werden nie ausgelöst.Fragmente in TabLayout binden nicht an Viewmodel

Ich habe einen Blick bekam, die eine TabLayout hält, wie Sie unten sehen können:

<?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> 

Die TabView Code:

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; 
      } 
     } 
    } 
} 

.. und es ist Ansichtsmodell:

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(); 
      }); 
     } 
    } 
} 

Eines der beteiligten Fragmente:

<?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> 

Der Code Login-Fragment:

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); 
     } 
    } 
} 

.. und seine Basisklasse:

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; } 
    } 
} 

Das Ansichtsmodell:

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")); 
     } 
    } 
} 

und (ein Teil) die Basisklasse:

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; } 

     ... 
    } 
} 

Hier ist der 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]; 
     //} 
    } 
} 

Antwort

0

Sie benötigen BindingInflate() anstelle des Standard-Android inflater zu verwenden, da sie nicht wissen, wie die MvxBind Eigenschaften zu verarbeiten.

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; 
} 
+0

Ah, ich hatte das schon mal irgendwo in einem Kommentar gesehen. Ich habe es bei diesem Gedanken nicht gefunden und habe nie gemerkt, dass es eine Erweiterungsmethode ist. Wenn ich das Snippet füge bekomme ich eine NullReferenceException –

+0

Es scheint, dass ich auch die base.OnCreateView benötigt, da jetzt es funktioniert. Vielen Dank –

Verwandte Themen