Reputation: 521
Apologies for a repeated question, I have seen many questions about this but I've not been successful implementing other solutions in my scenario. I'm still getting my head around MVVM, in some instances I've got data binding working but in other instances (like now) I cannot make sense of it.
Every solution I find for data-binding, people always suggest ensuring OnPropertyChanged() is being called - this is always the answer for other solutions I've looked at, but in my case I already have this so I'm super confused. I know the bind works initially when I open the page, and my ICommand always works fine - it's just updating dating the UI appropriately.
What I'm doing is, allowing the user to toggle the which will navigate the user to the OS Settings page (iOS). From there they can make some changes as they wish, but when they come back to my application I'm double checking if they made the changes as expected, otherwise if they have not revert the toggle switch back to whatever result I get from checking. Stepping into the business logic, this work a charm. My boolean value is ALWAYS what I expect it to be, but the UI just never reflects this.
SettingsPage.xaml
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:d="http://xamarin.com/schemas/2014/forms/design"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
xmlns:behaviour="clr-namespace:OCS.Behaviours"
x:Class="OCS.Views.SettingsPage"
Title="Settings">
<ContentPage.Content>
<StackLayout>
<Switch VerticalOptions="Center" IsToggled="{Binding IsPushNotificationsAllowed}">
<Switch.Behaviors>
<behaviour:EventToCommandBehaviour EventName="Toggled" Command="{Binding PushNotificationsCommand}" />
</Switch.Behaviors>
</Switch>
</StackLayout>
</ContentPage.Content>
</ContentPage>
SettingsPage.xaml.cs
namespace OCS.Views {
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class SettingsPage : ContentPage {
private SettingsViewModel settingsViewModel;
public SettingsPage() {
InitializeComponent();
settingsViewModel = new SettingsViewModel();
BindingContext = settingsViewModel;
}
protected override void OnAppearing() {
base.OnAppearing();
MessagingCenter.Unsubscribe<App>(this, "UpdateUI");
MessagingCenter.Subscribe<App>(this, "UpdateUI", (sender) => settingsViewModel.UpdateUI());
}
}
}
SettingsViewModel.cs:
namespace OCS.ViewModel {
public class SettingsViewModel : BaseViewModel {
private Boolean isPushNotificationsAllowed;
public Boolean IsPushNotificationsAllowed { get=> isPushNotificationsAllowed; set => SetValue(ref isPushNotificationsAllowed, value); }
public ICommand PushNotificationsCommand => new Command(OnPushNotificationToggled);
public SettingsViewModel() => UpdateUI();
public async void UpdateUI() {
IsPushNotificationsAllowed = await DependencyService.Get<IPermissions>().IsPushNotificationsEnabled();
}
private void OnPushNotificationToggled() {
Preferences.Set("OnSleepBlock", true);
DependencyService.Get<IPermissions>().OpenOSSettingsForPermissionChange();
}
}
}
BaseViewModel.cs
namespace OCS.ViewModel {
public class BaseViewModel {
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged([CallerMemberName] String propertyName = null) {
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
protected void SetValue<T>(ref T backingField, T value, [CallerMemberName] String propertyName = null) {
if (EqualityComparer<T>.Default.Equals(backingField, value)) {
return;
}
backingField = value;
OnPropertyChanged(propertyName);
}
private Boolean isBusy = false;
public Boolean IsBusy { get => isBusy; set => SetValue(ref isBusy, value); }
}
}
App.xaml.cs
protected override void OnResume() {
MessagingCenter.Send<App>(this, "UpdateUI");
}
Upvotes: 0
Views: 585
Reputation: 521
As pointed out by miechooy in the comments of my original post, I was missing the INotifyPropertyChanged in my BaseViewModel.cs
Before:
public class BaseViewModel { }
After:
public class BaseViewModel : INotifyPropertyChanged { }
Upvotes: 1