I am working on a Xamarin project that runs with MvvmCross. I am trying to add a preference view inside Android but I cannot get it to work.
When I try to navigate to the MvxPreferenceFragment
, I get the following errors:
[0:] mvx:Diagnostic: 12.11 Activity host with ViewModelType PreferenceTest.Droid.Activities.MainPreferenceActivity is not CurrentTopActivity. Showing Activity before showing Fragment for PreferenceTest.Core.ViewModels.Fragments.PreferenceViewModel
An unhandled exception occured.
09-26 13:54:45.753 I/MonoDroid(12779): UNHANDLED EXCEPTION:
09-26 13:54:45.810 I/MonoDroid(12779): System.Collections.Generic.KeyNotFoundException: Could not find view for PreferenceTest.Droid.Activities.MainPreferenceActivity
09-26 13:54:45.810 I/MonoDroid(12779): at MvvmCross.Core.Views.MvxViewsContainer.GetViewType (System.Type viewModelType) [0x0006a] in C:\projects\mvvmcross\MvvmCross\Core\Core\Views\MvxViewsContainer.cs:72
09-26 13:54:45.810 I/MonoDroid(12779): at MvvmCross.Droid.Support.V7.AppCompat.MvxAppCompatViewPresenter.ShowHostActivity (MvvmCross.Droid.Views.Attributes.MvxFragmentPresentationAttribute attribute) [0x00000] in C:\projects\mvvmcross\MvvmCross-AndroidSupport\MvvmCross.Droid.Support.V7.AppCompat\MvxAppCompatViewPresenter.cs:166
09-26 13:54:45.810 I/MonoDroid(12779): at MvvmCross.Droid.Support.V7.AppCompat.MvxAppCompatViewPresenter.ShowFragment (System.Type view, MvvmCross.Droid.Views.Attributes.MvxFragmentPresentationAttribute attribute, MvvmCross.Core.ViewModels.MvxViewModelRequest request) [0x0007d] in C:\projects\mvvmcross\MvvmCross-AndroidSupport\MvvmCross.Droid.Support.V7.AppCompat\MvxAppCompatViewPresenter.cs:196
09-26 13:54:45.810 I/MonoDroid(12779): at MvvmCross.Droid.Views.MvxAndroidViewPresenter.<RegisterAttributeTypes>b__39_2 (System.Type view, MvvmCross.Core.Views.MvxBasePresentationAttribute attribute, MvvmCross.Core.ViewModels.MvxViewModelRequest request) [0x00000] in C:\projects\mvvmcross\MvvmCross\Droid\Droid\Views\MvxAndroidViewPresenter.cs:188
09-26 13:54:45.810 I/MonoDroid(12779): at MvvmCross.Droid.Views.MvxAndroidViewPresenter.Show (MvvmCross.Core.ViewModels.MvxViewModelRequest request) [0x00055] in C:\projects\mvvmcross\MvvmCross\Droid\Droid\Views\MvxAndroidViewPresenter.cs:295
09-26 13:54:45.810 I/MonoDroid(12779): at MvvmCross.Droid.Views.MvxAndroidViewDispatcher+<>c__DisplayClass2_0.<ShowViewModel>b__0 () [0x00000] in C:\projects\mvvmcross\MvvmCross\Droid\Droid\Views\MvxAndroidViewDispatcher.cs:26
09-26 13:54:45.810 I/MonoDroid(12779): at MvvmCross.Droid.Views.MvxAndroidMainThreadDispatcher.RequestMainThreadAction (System.Action action, System.Boolean maskExceptions) [0x00020] in C:\projects\mvvmcross\MvvmCross\Droid\Droid\Views\MvxAndroidMainThreadDispatcher.cs:20
09-26 13:54:45.811 I/MonoDroid(12779): at MvvmCross.Droid.Views.MvxAndroidViewDispatcher.ShowViewModel (MvvmCross.Core.ViewModels.MvxViewModelRequest request) [0x00014] in C:\projects\mvvmcross\MvvmCross\Droid\Droid\Views\MvxAndroidViewDispatcher.cs:26
09-26 13:54:45.811 I/MonoDroid(12779): at MvvmCross.Core.Navigation.MvxNavigationService+<Navigate>d__32.MoveNext () [0x0003a] in C:\projects\mvvmcross\MvvmCross\Core\Core\Navigation\MvxNavigationService.cs:179
09-26 13:54:45.811 I/MonoDroid(12779): --- End of stack trace from previous location where exception was thrown ---
09-26 13:54:45.811 I/MonoDroid(12779): at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw () [0x0000c] in <896ad1d315ca4ba7b117efb8dacaedcf>:0
09-26 13:54:45.811 I/MonoDroid(12779): at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess (System.Threading.Tasks.Task task) [0x0003e] in <896ad1d315ca4ba7b117efb8dacaedcf>:0
09-26 13:54:45.811 I/MonoDroid(12779): at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification (System.Threading.Tasks.Task task) [0x00028] in <896ad1d315ca4ba7b117efb8dacaedcf>:0
09-26 13:54:45.811 I/MonoDroid(12779): at System.Runtime.CompilerServices.TaskAwaiter.ValidateEnd (System.Threading.Tasks.Task task) [0x00008] in <896ad1d315ca4ba7b117efb8dacaedcf>:0
09-26 13:54:45.811 I/MonoDroid(12779): at System.Runtime.CompilerServices.ConfiguredTaskAwaitable+ConfiguredTaskAwaiter.GetResult () [0x00000] in <896ad1d315ca4ba7b117efb8dacaedcf>:0
09-26 13:54:45.811 I/MonoDroid(12779): at MvvmCross.Core.Navigation.MvxNavigationService+<Navigate>d__40.MoveNext () [0x00078] in C:\projects\mvvmcross\MvvmCross\Core\Core\Navigation\MvxNavigationService.cs:293
09-26 13:54:45.811 I/MonoDroid(12779): --- End of stack trace from previous location where exception was thrown ---
09-26 13:54:45.811 I/MonoDroid(12779): at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw () [0x0000c] in <896ad1d315ca4ba7b117efb8dacaedcf>:0
09-26 13:54:45.811 I/MonoDroid(12779): at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess (System.Threading.Tasks.Task task) [0x0003e] in <896ad1d315ca4ba7b117efb8dacaedcf>:0
09-26 13:54:45.811 I/MonoDroid(12779): at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification (System.Threading.Tasks.Task task) [0x00028] in <896ad1d315ca4ba7b117efb8dacaedcf>:0
09-26 13:54:45.811 I/MonoDroid(12779): at System.Runtime.CompilerServices.TaskAwaiter.ValidateEnd (System.Threading.Tasks.Task task) [0x00008] in <896ad1d315ca4ba7b117efb8dacaedcf>:0
09-26 13:54:45.811 I/MonoDroid(12779): at System.Runtime.CompilerServices.TaskAwaiter.GetResult () [0x00000] in <896ad1d315ca4ba7b117efb8dacaedcf>:0
09-26 13:54:45.811 I/MonoDroid(12779): at PreferenceTest.Core.ViewModels.FirstViewModel+<ExecutePreferences>d__8.MoveNext () [0x00026] in C:\git\PreferenceTest\PreferenceTest\PreferenceTest\PreferenceTest.Core\ViewModels\FirstViewModel.cs:28
09-26 13:54:45.811 I/MonoDroid(12779): --- End of stack trace from previous location where exception was thrown ---
09-26 13:54:45.811 I/MonoDroid(12779): at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw () [0x0000c] in <896ad1d315ca4ba7b117efb8dacaedcf>:0
09-26 13:54:45.811 I/MonoDroid(12779): at System.Runtime.CompilerServices.AsyncMethodBuilderCore+<>c.<ThrowAsync>b__6_0 (System.Object state) [0x00000] in <896ad1d315ca4ba7b117efb8dacaedcf>:0
09-26 13:54:45.811 I/MonoDroid(12779): at Android.App.SyncContext+<>c__DisplayClass2_0.<Post>b__0 () [0x00000] in <2e14bb2dd93a405e81838369ed72695b>:0
09-26 13:54:45.811 I/MonoDroid(12779): at Java.Lang.Thread+RunnableImplementor.Run () [0x00008] in <2e14bb2dd93a405e81838369ed72695b>:0
09-26 13:54:45.811 I/MonoDroid(12779): at Java.Lang.IRunnableInvoker.n_Run (System.IntPtr jnienv, System.IntPtr native__this) [0x00008] in <2e14bb2dd93a405e81838369ed72695b>:0
09-26 13:54:45.811 I/MonoDroid(12779): at (wrapper dynamic-method) System.Object:a278159c-f25c-4da4-ac29-d4bae0d2de73 (intptr,intptr)
This is the code I am trying to run (for the full code please refer to the github link below): First I created a view inside the xml folder (named preference.xml)
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
<EditTextPreference android:title="Your Name"
android:key="username"
android:summary="Please provide your username"></EditTextPreference>
<CheckBoxPreference android:title="Application Updates"
android:defaultValue="false"
android:summary="This option if selected will allow the application to check for latest versions."
android:key="applicationUpdates" />
<ListPreference android:title="Download Details"
android:summary="Select the kind of data that you would like to download"
android:key="downloadType"
android:defaultValue="1"
android:entries="@array/listArray"
android:entryValues="@array/listValues" />
<CheckBoxPreference
android:key="prefer wifi"
android:title="Prefer WiFi" />
</PreferenceScreen>
Also the fragment code:
[MvxFragmentPresentation(typeof(MainPreferenceActivity), Resource.Id.content_frame, true)]
[Register(nameof(PreferenceFragment))]
public class PreferenceFragment : MvxPreferenceFragment<PreferenceViewModel>
{
public override View OnCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
base.OnCreateView(inflater, container, savedInstanceState);
var view = this.BindingInflate(Resource.Xml.preferences, container, false);
return view;
}
}
The call is made with the navigation service:
private async void ExecutePreferences()
{
await _navigationService.Navigate<PreferenceViewModel>();
}
I cannot find what is wrong with this code :).
Here is also a github link to the sample.
The first issue is with the use of the MvxFragmentPresentation
the first parameter is the type of the ViewModel
being used for the host activity and not the type of the activity itself. Which in your case would be MainPreferenceViewModel
.
The next issue is that as you are using the MvxAppCompatViewPresenter
presenter and so you will need to use MvxPreferenceFragmentCompat
. MvxPreferenceFragmentCompat
can be found in the MvvmCross.Droid.Support.V7.Preference
NuGet package.
[MvxFragmentPresentation(typeof(MainPreferenceViewModel), Resource.Id.content_frame)]
[Register(nameof(PreferenceFragment))]
public class PreferenceFragment : MvxPreferenceFragmentCompat<PreferenceViewModel>
{
public override void OnCreatePreferences(Bundle savedInstanceState, string rootKey)
{
SetPreferencesFromResource(Resource.Xml.preferences, rootKey);
}
}
Lastly you would need to specify a theme for the preferences in your activity
<item name="preferenceTheme">@style/PreferenceThemeOverlay.v14.Material</item>
I have gone with a material design theme from the Xamarin.Android.Support.v14.Preference
but you could have also used one of the other ones:
@style/PreferenceThemeOverlay
@style/PreferenceThemeOverlay.v14
See pull request for full details of changes.