Reputation: 75
I have a ViewModel like this
Public class AboutPageViewModel
{
public AboutPageViewModel()
{
AppName = Settings.MyAppName;
}
private string _appName;
public string AppName
{
get{return _appName;}
set{_appName = value; RaisePropertyChanged("AppName");}
}
}
Now in a static class
public static class Settings
{
public static string MyAppName{get;set;} = "LOL"
}
How do I notify the ViewModel everytime MyAppName is changed, and update it to the Binded UI?
Thanks!
Upvotes: 0
Views: 444
Reputation: 37059
As you define it in your question, Settings
isn't a static class (ah, I see in comments that was a typo, and it's static in your code). It should not be static. PropertyChanged notifications on a static class are theoretically possible but it's not worth your time to mess with, and there's no need to bother.
Have Settings
implement INotifyPropertyChanged
, just like your viewmodel. When MyAppName
changes, Settings
should raise PropertyChanged
, just as AboutPageViewModel
does when its own AppName
property changes.
Now give Settings
a static property called Instance
:
public static Settings Instance { get; private set; }
static Settings()
{
Instance = new Settings();
}
And handle its PropertyChanged
event in AboutPageViewModel
:
public AboutPageViewModel()
{
AppName = Settings.Instance.MyAppName;
Settings.Instance.PropertyChanged += (s,e) =>
{
// If you're in C#6:
//if (e.PropertyName == nameof(Settings.MyAppName))
if (e.PropertyName == "MyAppName")
{
AppName = Settings.Instance.MyAppName;
}
}
}
Arguably a better option; I've done it this way more than once.
In comments, @MikeEason makes the very good point that this could also be done with a custom *Changed
event such as MyAppNameChanged
, which has two advantages: It lets you go back to a static class, and it lets you skip the check on the property name, which is extra code and also a "magic string". Working with INotifyPropertyChanged
we get a little bit numb to the danger of magic strings, but they are in fact bad. If you're in C#6, you can and absolutely should use the nameof()
operator, but not all of us are in C#6 just yet. My main responsibility at work is an application that we're hoping to migrate to C#6 this summer.
public static event EventHandler<String> MyAppNameChanged;
private static String _myAppName = "";
public static String MyAppName {
get { return _myAppName; }
set {
if (_myAppName != value)
{
_myAppName = value;
// C#6 again. Note (thanks OP!) you can't pass this for sender
// in a static property.
MyAppNameChanged?.Invoke(null, value);
}
}
}
The drawback of this is that, well, this class is called Settings
, not Setting
. Maybe it's got a dozen properties changing here and there. That gets to be a real thicket of distinct property-changed events ("so what?" you may ask -- and you may have a point). My tendency is to stick with PropertyChanged
if there's a whole sheaf of them, and to add an event if the class has only one or two important properties that somebody needs to keep an eye on. Either way is annoying in my view; try both and you'll eventually settle on a preference.
Upvotes: 4
Reputation: 21999
You don't need to store value in ViewModel if you already have it somewhere (I assume what you are not going to change it in ViewModel itself):
public class AboutPageViewModel : INotifyPropertyChanged
{
public string AppName => Settings.MyAppName;
}
And as for View to know when this property is changed you need 2 things: 1) there should be a way to inform ViewModel when value is changed 2) rise PropertyChanged(nameof(AppName))
(notice INotifyPropertyChanged
).
Several possibilities to make it:
Settings
should rise event when MyAppName
value is changed, ViewModel subscribe to it and rises PropertyChanged
;INotifyPropertyChanged
, bind to that type property instead, this will update view automatically if that type rises PropertyChanged
.Upvotes: 2
Reputation: 1004
You have to implement INotifyPropertyChanged interface on Settings class!
then use the same piece of code like this:
private string _myAppName;
public string MyAppName
{
get{return _myAppName;}
set{_appName = value; RaisePropertyChanged("MyAppName");}
}
Upvotes: 0