MvvmCross / MvvmCross-AndroidSupport

Android support library packages for MvvmCross: The .NET MVVM framework for cross-platform solutions.
http://mvvmcross.com
15 stars 0 forks source link

No view model association found for candidate view Exception #301

Closed danieleardissone closed 7 years ago

danieleardissone commented 7 years ago

Hi all, I'm trying to convert in MvvmCross 4 an old Xamarin Android project that use MvvmCross 3.5. I followed the sample provided by @martijn00 to manage fragments but I get this exception during the loading process of the app:

[0:] mvx:Diagnostic: 32,48 No view model association found for candidate view SettingsFragment
[0:] mvx:Warning: 32,59 Exception masked ArgumentNullException: Value cannot be null.
Parameter name: key
      at System.ThrowHelper.ThrowArgumentNullException (System.ExceptionArgument argument) [0x00000] in /Users/builder/data/lanes/3819/96c7ba6c/source/mono/mcs/class/referencesource/mscorlib/system/throwhelper.cs:80 
  at System.Collections.Generic.Dictionary`2[TKey,TValue].Insert (TKey key, TValue value, System.Boolean add) [0x0000b] in /Users/builder/data/lanes/3819/96c7ba6c/source/mono/mcs/class/referencesource/mscorlib/system/collections/generic/dictionary.cs:322 
  at System.Collections.Generic.Dictionary`2[TKey,TValue].Add (TKey key, TValue value) [0x00000] in /Users/builder/data/lanes/3819/96c7ba6c/source/mono/mcs/class/referencesource/mscorlib/system/collections/generic/dictionary.cs:192 
  at System.Linq.Enumerable.ToDictionary[TSource,TKey,TElement] (System.Collections.Generic.IEnumerable`1[T] source, System.Func`2[T,TResult] keySelector, System.Func`2[T,TResult] elementSelector, System.Collections.Generic.IEqualityComparer`1[T] comparer) [0x0004d] in /Users/builder/data/lanes/3819/96c7ba6c/source/mono/mcs/class/referencesource/System.Core/System/Linq/Enumerable.cs:881 
  at System.Linq.Enumerable.ToDictionary[TSource,TKey,TElement] (System.Collections.Generic.IEnumerable`1[T] source, System.Func`2[T,TResult] keySelector, System.Func`2[T,TResult] elementSelector) [0x00000] in /Users/builder/data/lanes/3819/96c7ba6c/source/mono/mcs/class/referencesource/System.Core/System/Linq/Enumerable.cs:873 
  at MvvmCross.Droid.Shared.Presenter.FragmentHostRegistrationSettings.InitializeIfNeeded () [0x00128] in <1e7e1ef3d69e46878507571feff3954e>:0 
  at MvvmCross.Droid.Shared.Presenter.FragmentHostRegistrationSettings.IsTypeRegisteredAsFragment (System.Type viewModelType) [0x00000] in <1e7e1ef3d69e46878507571feff3954e>:0 
  at MvvmCross.Droid.Shared.Presenter.MvxFragmentsPresenter.Show (MvvmCross.Core.ViewModels.MvxViewModelRequest request) [0x0000c] in <1e7e1ef3d69e46878507571feff3954e>:0 
  at MvvmCross.Droid.Views.MvxAndroidViewDispatcher+<>c__DisplayClass2_0.<ShowViewModel>b__0 () [0x00000] in <c9cff602f1404a9da5c69389736fa297>:0 
  at MvvmCross.Droid.Views.MvxAndroidMainThreadDispatcher.RequestMainThreadAction (System.Action action) [0x00019] in <c9cff602f1404a9da5c69389736fa297>:0 
  at MvvmCross.Droid.Views.MvxAndroidViewDispatcher.ShowViewModel (MvvmCross.Core.ViewModels.MvxViewModelRequest request) [0x00014] in <c9cff602f1404a9da5c69389736fa297>:0 
  at MvvmCross.Core.ViewModels.MvxNavigatingObject.ShowViewModelImpl (System.Type viewModelType, MvvmCross.Core.ViewModels.IMvxBundle parameterBundle, MvvmCross.Core.ViewModels.IMvxBundle presentationBundle, MvvmCross.Core.ViewModels.MvxRequestedBy requestedBy) [0x0002e] in <d0a13790d5ea483b82d6b8b761bde552>:0 
  at MvvmCross.Core.ViewModels.MvxNavigatingObject.ShowViewModel (System.Type viewModelType, MvvmCross.Core.ViewModels.IMvxBundle parameterBundle, MvvmCross.Core.ViewModels.IMvxBundle presentationBundle, MvvmCross.Core.ViewModels.MvxRequestedBy requestedBy) [0x00000] in <d0a13790d5ea483b82d6b8b761bde552>:0 
  at MvvmCross.Core.ViewModels.MvxNavigatingObject.ShowViewModel[TViewModel] (MvvmCross.Core.ViewModels.IMvxBundle parameterBundle, MvvmCross.Core.ViewModels.IMvxBundle presentationBundle, MvvmCross.Core.ViewModels.MvxRequestedBy requestedBy) [0x00000] in <d0a13790d5ea483b82d6b8b761bde552>:0 
  at MvvmCross.Core.ViewModels.MvxAppStart`1[TViewModel].Start (System.Object hint) [0x00013] in <d0a13790d5ea483b82d6b8b761bde552>:0 
  at MvvmCross.Droid.Views.MvxSplashScreenActivity.TriggerFirstNavigate () [0x00005] in <c9cff602f1404a9da5c69389736fa297>:0 
  at MvvmCross.Droid.Views.MvxSplashScreenActivity.InitializationComplete () [0x00009] in <c9cff602f1404a9da5c69389736fa297>:0 
  at MvvmCross.Droid.Platform.MvxAndroidSetupSingleton.<InitializeFromSplashScreen>b__7_1 () [0x0000a] in <c9cff602f1404a9da5c69389736fa297>:0 
  at MvvmCross.Platform.Core.MvxMainThreadDispatcher.ExceptionMaskedAction (System.Action action) [0x00000] in D:\git\MvvmCross\MvvmCross\Platform\Platform\Core\MvxMainThreadDispatcher.cs:22

Debugging the code I noticed that it happens immediately after the Android Setup. Using the right annotations in the fragment like the sample, I expect that MvvmCross maps every fragment with the corresponding view model but seems that it's not happening. Do I have to explicitely force this mapping in a specific way? Any idea about what am I doing wrong?

I'm using MvvmCross 4.3.0 and the latest stable Xamarin release, of course.

My fragment definition:

[MvxFragment((typeof(FragmentsHostViewModel)), Resource.Id.content_frame)] //, true)]
[Register("molloofficina.droid.views.fragments.SettingsFragment")]
public class SettingsFragment : BaseFragment<SettingsViewModel>
{
    protected override int FragmentId => Resource.Layout.SettingsView;
}

Presenter definition in Setup.cs:

protected override IMvxAndroidViewPresenter CreateViewPresenter()
{
    var mvxFragmentsPresenter = new MvxFragmentsPresenter(AndroidViewAssemblies);
    Mvx.RegisterSingleton<IMvxAndroidViewPresenter>(mvxFragmentsPresenter);
    return mvxFragmentsPresenter;
}

Thanks.

Daniele

martijn00 commented 7 years ago

Do you have a reproduction repo so i could test this?

danieleardissone commented 7 years ago

Yes, I just created MvxAndroidFragmentsTest. It's a smaller version of my application that contains just the files to reproduce the problem. I hope it could be enough to understand what's going wrong with it. Thank you.

prin53 commented 7 years ago

Are there any updates?

prin53 commented 7 years ago

@danieleardissone, you have a SettingsFragment but SettingsViewModel. Lookup mechanism uses class naming, so you need to have SettingsView. Or just add the ViewModel type at the fragment attribute:

[MvxFragment((typeof(FragmentsHostViewModel)), Resource.Id.content_frame), ViewModelType = typeof(SettingsViewModel)]
[Register("mvxandroidfragmentstest.droid.views.fragments.SettingsFragment")]
public class SettingsFragment : BaseNavigationFragment<SettingsViewModel>
{
}
danieleardissone commented 7 years ago

Thank you @Prin53 now it works! I didn't know how to specify the viewmodel type for a fragment with a different class name.