call PropertyChange with public member, not string C# - c#

I've looked around a bit online and wasn't able to easily find a solution to what i was looking for. It may be in part to me not being sure the terminology to search for.
I wanted to know is there a way to call the PropertyChanged event using the property member name like so...
private string height;
public string Height
{
get { return name; }
set
{
Set(ref height, value);
RaisePropertyChanged( ()=> Name);
}
}
rather than using the actual string which can be seen here..
private string height;
public string Height
{
get { return name; }
set
{
Set(ref height, value);
RaisePropertyChanged("Name");
}
}
Raise Event
protected void RaisePropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
I've attempted a solution to this, but wasn't able to come to a conclusion. I know there are methods out there somewhere and im sure there are more modern ways to do this. Its 2016!!

Since you appear to be using C# 6, you can use the nameof operator, which resolves the name of the referenced property at compile time, passing a string to your method.
RaisePropertyChanged(nameof(Name));
If you need to use an earlier C# compiler, you can resolve the name of the property through a lambda expression; this is what Entity Framework does for its Include operator. You can define a GetPropertyName utility method (see example), then call it like so:
RaisePropertyChanged(GetPropertyName(() => Name));

Related

simplest and most concise form to write a property in C#9 and c#10

What is the simplest and most concise form to write a property as follows, considering the features of C#9 or even C#10?
Is it possible without using the backing field?
string fName;
public string Name { get { return fName; } set { SetPropertyValue<string>(nameof(Name), ref fName, value); } }
public string Name {get;}
Should be the simplest you can do.
If you need support for WPFs PropertyChanged I usually do
private string name;
public string Name {get => name; set => Set(ref name, value); }
private void Set<T>(ref T field, T value, [CallerMemberName]string caller = "")
{
field = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(caller ));
}
Optionally add a comparison inside the Set method to only raise the event if the new value is not equal to the old value. As far as I know there is nothing new in c# 9 or 10 that improves this.

Using string constant for notify property changed

I am working with some existing code and trying to figure out the advantage (if any) of using a string constant for the name of a property when implementing INotifyPropertyChanged interface.
So for example doing this:
/*
* Why use this instead of string literal
* in OnPropertyChanged below??
*/
public const string CustomerIdPropertyName = "CustomerId";
private int _customerId;
public int CustomerId
{
get
{
return _customerId;
}
set
{
if (_cusomterId != value)
{
_customerId = value;
OnPropertyChanged(CustomerIdPropertyName);
}
}
}
Instead of this:
private int _customerId;
public int CustomerId
{
get
{
return _customerId;
}
set
{
if (_cusomterId != value)
{
_customerId = value;
OnPropertyChanged("CustomerId");
}
}
}
Both versions are equally prone to typing errors.
If you have a somewhat recent version of .NET, your property changed handler should look like this:
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
var handler = this.PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
Then your property looks like this:
private int _customerId;
public int CustomerId
{
get
{
return _customerId;
}
set
{
if (_cusomterId != value)
{
_customerId = value;
this.OnPropertyChanged();
}
}
}
And you don't have any trouble with typing errors.
There isn't an advantage compiler wise, since both will end up being a constant value.
I can't imagine a real advantage in using the code like that way. Either ways it is easy to make a typo, and you are not going to reuse that constant for anything, so it is pointless.
I had love to see the new nameof keyword implement in the next version of .NET. Or even better, if possible, use [CallerMemberName] as Marc Gravell suggested.
The use of nameof will be useful when having custom calculated properties (like in WPF for example) that don't have their own getter / setter.
To answer your question (trying to figure out the advantage) : there is an advantage for an observer who know your type and wait for a specific property to change
void Observe(Customer c)
{
c.PropertyChanged += (s, e) =>
{
if (e.PropertyName == Customer.CustomerIdPropertyName)
{
MessageBox.Show("New id " + Customer.CustomerId);
}
}
}
If you want to go futher :
Typing errors can be avoided using a property selector expression to fill your CustomerIdPropertyName.
You won't need it with nameof keyword (CTP). If you don't have this kind of observer, CalleMemberNameAttribute is the easiest way.
I imagine it is just to avoid bugs caused by typos and try and make the code a little easier to read. Also if you change the name of the property it means changing the value of the const will then work for all code that is checking if the property has changed. e.g. imagine this code:
public void Main()
{
var obj = new ClassWithNotifier();
obj.OnPropertyChanged += ObjectPropertyChanged;
DoSomethingWithObj(obj);
}
private void ObjectPropertyChanged(string propertyName)
{
switch (propertyName) {
case ClassWithNotifier.CustomerIdPropertyName:
// If the constant changes this will still work
break;
case "SomeOtherPropertyName":
// If you change the property string that is passed here from
// your class ClassWithNotifier then this will now break
break;
}
}
In the example above, regardless of the value of the constant the code will work, and if you want to change the property name at some point then you only need to change the constant value and everything will still work with out having to find everywhere we are checking for the name (obviously if you want to change the name of the constant variable as well then you still need to find those references, but finding references to Public fields is easier than searching through the whole project for magic strings)

MVVM CallerMemberName and "magic strings"

New C# 5.0 release introduced something to get rid of "magic strings" in INotifyPropertyChanged implementation like:
OnPropertyChanged("CustomerName");
Now it is possible to write just:
OnPropertyChanged();
It is possible due to CallerMemberName in method definition:
protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
{ ... }
It is much more refactoring friendly than "magic strings" way and faster than lambda expressions, but I wonder how can we call multiple times OnPropertyChanged from one set accessor. For example if we wanted something like this:
public int Width
{
get
{
return width;
}
set
{
width = value;
OnPropertyChanged("Width");
OnPropertyChanged("Height");
}
}
How can we do this with CallerMemberName way and avoid using "magic strings" and lambda expressions?
I also wonder how can we avoid using "magic strings" in IDataError info:
public string Error
{
get;
private set;
}
public string this[string columnName]
{
get
{
if (columnName == "Name")
{
if (String.IsNullOrWhiteSpace(Name))
Error = "Name cannot be null or empty.";
else
Error = null;
}
return Error;
}
}
I am new to MVVM so maybe I overlooked some clever way to deal with "magic strings", however I did some research and found nothing.
The simple answer is, that you can't do that. As the name CallerMemberName indicates, it will contain the name of the caller.
For cases where you want to raise PropertyChanged for another than the current one, you will have to use one of the "old" ways.
In IDataErrorInfo you also have to use one of those ways, there is no alternative.
I know this question is about C# 5.0, but if people still have questions of thise nature please check out c# 6.0. C# 6.0 Has a great way to solve this problem. Check out the nameof keyword. I wrote a little post about it if anyone is interested: c# 6.0 solves magic strings problem
This will help:
"Kind Of Magic"
Effortless INotifyPropertyChanged
http://visualstudiogallery.msdn.microsoft.com/d5cd6aa1-57a5-4aaa-a2be-969c6db7f88a
as an example for adding it to one property:
[Magic]
public string Name { get { return _name; } set { _name = value; } }
string _name;
Another example for adding it to all the class properties:
[Magic]
public class MyViewModel: INotifyPropertyChanged
{
public string Name { get; set; }
public string LastName { get; set; }
.....
}

How to write MVVM properties?

With MVVM I always see these both methods for properties:
private int myProperty;
public int MyProperty
{
get { return myProperty; }
set
{
myProperty = value;
NotifyPropertyChanged("MyProperty");
}
}
and
private int myProperty;
public int MyProperty
{
get { return myProperty; }
set
{
myProperty = value;
NotifyPropertyChanged(m => m.MyProperty);
}
}
The first one use an hardcoded string to NotifyPropertyChanged and the second one use a lambda expression to NotifyPropertyChanged. I don't want to create a debate to ask what is the better solution but I would like to understand what are the differences bewteeen these two solution. What are the consequences of using one or the other?
Correct me if I'm wrong but the lambda expression solution should use more memory and should be slower than the hardcoded string because the NotifyPropertyChanged method of the base class use delegate and reflection. But the hardcoded string solution may create stupid bug because it's a string and nothing to tell me I correctly wrote it.
The second expression would either generate a compiler error on the property name change, or would automatically change with it (via the Rename support in VS or ReSharper).
So basically, you gain compiler support for property names. The wrong name provided to the notify would mean that data-binding would break. With string names, this breakage would be silent.
In a small UI the choice is irrelevant in my opinion, but in a large application with a heavy UI layer the extra support against bugs can pay itself off in the long run.
Performance won't be problematically slower, don't forget, binding is reflection-powered anyway. Performance, as always, is relative. The hard-coded version will technically be faster because it doesn't need to reflect the property name out of the meta-data. How much faster, I'm not sure.
Rather than repeating that code of NotifyPropertyChanged for every property, I felt the below code is more cleaner
Create a Set method in your ViewModel Base
protected bool Set<T>(Expression<Func<T>> selectorExpression, ref T field, T value)
{
if (EqualityComparer<T>.Default.Equals(field, value))
return false;
field = value;
RaisePropertyChanged(selectorExpression);
return true;
}
and use them as
string title;
public string Title
{
get { return title; }
set { Set(() => Title, ref title, value); }
}
I use the following method in a base class implementing INotifyPropertyChanged and it is so easy and convenient:
public void NotifyPropertyChanged()
{
StackTrace stackTrace = new StackTrace();
MethodBase method = stackTrace.GetFrame(1).GetMethod();
if (!(method.Name.StartsWith("get_") || method.Name.StartsWith("set_")))
{
throw new InvalidOperationException("The NotifyPropertyChanged() method can only be used from inside a property");
}
string propertyName = method.Name.Substring(4);
RaisePropertyChanged(propertyName);
}

Is it possible to use attributes to automatically raise an event on a property change

I find myself writing this code a lot:
private int _operationalPlan;
public int OperationalPlan
{
get
{
return _operationalPlan;
}
set
{
_operationalPlan = value;
RaisePropertyChanged();
}
}
private void RaisePropertyChanged()
{
if (PropertyChanged != null)
{
PropertyChanged(this, new
PropertyChangedEventArgs("PlansSelected"));
}
}
I'm wondering whether it might be possible to write an attribute that could be added to the property to automatically raise the event. I.e. something like this:
[RaiseOnSet("ProperyChanged", "PropertyChangedEventArgs", "PlansSelected")]
public int OperationalPlan
{
get
{
return _operationalPlan;
}
set
{
_operationalPlan = value;
RaisePropertyChanged();
}
}
Before I go and try to implement this I was wondering:
Is this facility in the .net framework
Has anyone tried to this facility
If it's possible
If there are any dead ends that I should avoid
To do that, you would need an AOP framework for .NET, like PostSharp or AOP.NET
I you are prepared to use a helper class to wrap the property values you can do this. But that means any client accessing the property will need to unwrap the value.
Another route is to use a helper type, see WPF and WF using (different) DependencyProperty for this. But you don't get automatically implemented properties.

Categories