Reputation: 2543
I'd like to bind value of SwitchPreferenceCompat
control on PreferenceScreen
to the view model property with MvvmCross.
Binding for some controls like EditTextPreference
works perfectly, but for others (CheckBoxPreference
or SwitchPreferenceCompat
) unfortunately not. I can see in the debug log that the property value is not changed for these controls.
I use MvvmCross 6.0 and Xamarin.Android with Visual Studio for Mac 7.4.3 (build 10). Additionally, I use Xam.Plugins.Settings to store settings.
I run the app on Android Emulator running Android 8.0.
Settings fragment fragment_settings.axml:
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:local="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<PreferenceCategory
android:title="Basic settings">
<SwitchPreferenceCompat
android:key="notifications_switch"
android:title="Switch Preference"
android:summary="Switch Summary"
android:defaultValue="true" />
<CheckBoxPreference
android:key="notifications_checkbox"
android:title="Enable notifications"
android:summary="Do you want to receive push notifications?"
android:defaultValue="true" />
<EditTextPreference
android:key="username_edittext"
android:title="UserName"
android:summary="Summary"
android:dialogMessage="Give your username if you want"
android:defaultValue="" />
</PreferenceCategory>
</PreferenceScreen>
SettingsView.cs
using Android.Runtime;
using App.Core.ViewModels.Main;
using App.Core.ViewModels.Settings;
using MvvmCross.Platforms.Android.Presenters.Attributes;
using MvvmCross.Droid.Support.V7.Preference;
using MvvmCross.Binding.BindingContext;
using Android.OS;
using Android.Views;
using Android.Support.V7.Preferences;
namespace App.Droid.Views.Settings
{
[MvxFragmentPresentation(typeof(MainContainerViewModel),
Resource.Id.content_frame,
true,
Resource.Animation.abc_fade_in,
Resource.Animation.abc_fade_out,
Resource.Animation.abc_fade_in,
Resource.Animation.abc_fade_out)]
[Register(nameof(SettingsView))]
public class SettingsView : MvxPreferenceFragmentCompat<SettingsViewModel>// BaseFragment<SettingsViewModel>
{
public override View OnCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
var view = base.OnCreateView(inflater, container, savedInstanceState);
var notifPreference = (CheckBoxPreference)this.FindPreference("notifications_checkbox");
var switchPreference = (SwitchPreferenceCompat)this.FindPreference("notifications_switch");
var usernamePreference = (EditTextPreference)this.FindPreference("username_edittext");
var bindingSet = this.CreateBindingSet<SettingsView, SettingsViewModel>();
bindingSet.Bind(switchPreference)
.For(v => v.Checked)
.To(vm => vm.NotificationsEnabled);
bindingSet.Bind(notifPreference)
.For(v => v.Checked)
.To(vm => vm.NotificationsEnabled);
bindingSet.Bind(usernamePreference)
.For(v => v.Text)
.To(vm => vm.UserName);
bindingSet.Apply();
return view;
}
public override void OnCreatePreferences(Bundle savedInstanceState, string rootKey)
{
this.AddPreferencesFromResource(Resource.Layout.fragment_settings);
}
}
}
And finally the view model itself. SettingsViewModel.cs:
using System.Diagnostics;
using MvvmCross.Commands;
using MvvmCross.Navigation;
using Plugin.Settings;
using Plugin.Settings.Abstractions;
namespace App.Core.ViewModels.Settings
{
public class SettingsViewModel : MvxViewModel
{
private readonly IMvxNavigationService _navigationService;
private static ISettings AppSettings => CrossSettings.Current;
public IMvxAsyncCommand CloseCommand { get; private set; }
public SettingsViewModel(IMvxNavigationService navigationService)
{
Debug.WriteLine("View Settings showing");
_navigationService = navigationService;
CloseCommand = new MvxAsyncCommand(async () => await _navigationService.Close(this));
}
public string UserName
{
get => AppSettings.GetValueOrDefault(nameof(UserName), string.Empty);
set
{
Debug.WriteLine($"Setting property Username to {value}");
AppSettings.AddOrUpdateValue(nameof(UserName), value);
}
}
public bool NotificationsEnabled
{
get => AppSettings.GetValueOrDefault(nameof(NotificationsEnabled), false);
set
{
Debug.WriteLine($"Setting property NotificationsEnabled to {value}");
AppSettings.AddOrUpdateValue(nameof(NotificationsEnabled), value);
}
}
}
}
I tried adding switch in LinkerPleaseInclude.cs as suggested in mvvmcross binding on switch fails on release
public void Include(Switch @switch)
{
@switch.CheckedChange += (sender, args) => @switch.Checked = [email protected];
}
public void Include(SwitchPreferenceCompat switchPreference)
{
switchPreference.PreferenceChange += (sender, args) => switchPreference.Checked = !switchPreference.Checked;
}
Upvotes: 0
Views: 898
Reputation: 138
I believe that the problem does not lie with your bindings. The issue appears to be with how you apply the value of your view model property to the AppSettings. I have been able to successfully take your preference screen xml and apply a view and view model binding. The value of the viewmodel property updates when the switch button is clicked.
You can inspect the code which I used to do the successful binding here Github Repo
Upvotes: 1