Ahmar Ahmar - 2 months ago 12
C# Question

Cant understand the Implementation of INotifyPropertyChanged

I am just a newbie in C# and I read about the

INotifyPropertyChanged Event Handler
on MSDN Blog and searched here on "stackoverflow". But I don't really understand how to implement it in my code and how I have to bind the events and properties together.


I have already made a
BindingClass
with
INotifyPropertyChanged
and the code is:


namespace Testing.Pages
{
class BindingClass : INotifyPropertyChanged
{
private string _setting;
public event PropertyChangedEventHandler PropertyChanged;

public BindingClass()
{

}

public BindingClass(string value)
{
_setting = value;
}

public string SettingProperty
{
get { return _setting; }
set
{
_setting = value;
// calling OnPropertyChanged whenever the property gets updated

}
}

protected void OnPropertyChanged([CallerMemberName] string _setting = "")
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(_setting));
}
}
}




SettingsPage.xaml




<TextBlock x:Name="PopupText"
Grid.Row="0"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Margin="0,0,0,20"
Text="Your theme will be updated next time you start the app."
TextWrapping="Wrap"
Visibility="Collapsed">
<TextBlock.Resources>
<Storyboard x:Name="popup_animate">
<DoubleAnimation Duration="0:0:2"
Storyboard.TargetName="PopupText"
AutoReverse="True"
From="0.0"
To="1.0"
BeginTime="{x:Bind }"
Storyboard.TargetProperty="(TextBlock.Opacity)"
></DoubleAnimation>
</Storyboard>
</TextBlock.Resources>
</TextBlock>
<TextBlock Text="Change Theme?"
Margin="10,10,0,0"></TextBlock>
<RadioButton x:Name="DarkTheme_btn"
Click="ChangeTheme_btn_Click"
Content="Dark Theme"
Margin="10,0,0,0"
GroupName="theme"></RadioButton>
<RadioButton x:Name="LightTheme_btn"
Click="ChangeTheme_btn_Click"
Content="Light Theme"
Margin="10,0,0,0"
GroupName="theme"></RadioButton>


and the code-behind file
SettingsPage.xaml.cs
is:



namespace Testing.Pages
{

/// <summary>
/// An empty page that can be used on its own or navigated to within a Frame.
/// </summary>
public sealed partial class SettingsPage : Page
{
BindingClass notifyProperty = new BindingClass();

public SettingsPage()
{
this.InitializeComponent();
NavigationCacheMode = NavigationCacheMode.Enabled;
}

private void ChangeTheme_btn_Click(object sender, RoutedEventArgs e)
{
DataContext = notifyProperty;
int notifySettings = 0;
if ((bool)DarkTheme_btn.IsChecked)
{
notifySettings = 2;
AppSettings.saveThemeSettings(notifySettings);
PopupText.Visibility = Visibility.Visible;
popup_animate.Begin();
}
else if ((bool)LightTheme_btn.IsChecked)
{
notifySettings = 1;
AppSettings.saveThemeSettings(notifySettings);
PopupText.Visibility = Visibility.Visible;
popup_animate.Begin();
}
}
}
}


I am already using a
int notifySettings
to change the settings of the app in
LocalSettingsFolder
and every time on app restart it loads the settings in
App.xaml
. Every time I change the settings I call a function in another
class
and it changes the settings and a
animation
is played when I click one of those two
radiobuttons
in
SettingsPage.xaml
. This is the old method.


Now I want to bind these events together so that I don't have to use
int notifySettings
and the
PopupText
animation should play as it does already whenever the
Theme Settings
gets updated. This is how I can also learn about the
INotifyPropertyChanged Event
.


The
int notifySettings
passes a
int
value to change the setting accordingly.
1 = LightTheme and 2 = DarkTheme.



Here is the
Settings Class
:



namespace Testing.Pages
{
class AppSettings
{
public static void saveThemeSettings(int value)
{
ApplicationDataContainer themeSettings = ApplicationData.Current.LocalSettings;
StorageFolder localFolder = ApplicationData.Current.LocalFolder;
themeSettings.Values["AppThemeSetting"] = value.ToString();
}

public static string readThemeSettings()
{
ApplicationDataContainer localSettings = ApplicationData.Current.LocalSettings;
StorageFolder localFolder = ApplicationData.Current.LocalFolder;
string appSettingsString = "error, nothing found";
if (localSettings.Values.ContainsKey("AppThemeSetting"))
{
appSettingsString = localSettings.Values["AppThemeSetting"]?.ToString();
}
return appSettingsString;
}

public static void removeLocalSettings(string settingValue)
{
ApplicationData.Current.LocalSettings.Values.Remove(settingValue);
}

}

}


If there is still any ambiguity please let me know and I can try to explain further. I hope someone can help me on this.



Update:


I made changes to my project according to the answer by Danny Bogers but the required
Animation
does not start and I think it is because the function is not even being called. I made some more changes and tried to do things on my own but it didn't really work out so I am going to use my own method to do the changes until someone else comes up with a solution.

Answer

The PropertyChanged needs to know which property has changed, so you have to pass the name of it.

Make it look like this:

public string SettingProperty
{
    get { return _setting; }
    set
    {
        if(_setting != value) // Or String.Equals(_setting, value, ...)
        {
             _setting = value;
             OnPropertyChanged(); // Invoke using no argument.
        }
    }
}

protected void OnPropertyChanged([CallerMemberName] string propertyName = "")
{
    PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}

The OnPropertyChanged method uses a CallerMemberName attribute on its parameter that is also optional. This means the compiler will use this argument and replace ith with the actual name of the Caller. So dont pass any value yourself.

It is the equivalent of PropertyChanged("SettingProperty"). The Attribute however makes it safe to refractor.

Regarding the rest of your question: I bellieve that the question itself is too brought and consists of atleast more than one propblem. So once you fixed the propertychanged part, rather asked a new question with the specific problem.