Here is something I mocked up as an exercise. Originally inspired by Jon Skeet's blog post.
public static class ObjectExtensions {
public static string GetPropertyNameAndValue<T>(this T obj, out object value) {
System.Reflection.PropertyInfo[] objGetTypeGetProperties = obj.GetType().GetProperties();
if(objGetTypeGetProperties.Length == 1) {
value = objGetTypeGetProperties[0].GetValue(obj, null);
return objGetTypeGetProperties[0].Name;
} else
throw new ArgumentException("object must contain one property");
}
}
class Whatever {
protected void ChangeProperty<T>(object property, T newValue, Action change) {
object value;
var name = property.GetPropertyNameAndValue(out value);
if(value == null && newValue != null || value != null && !value.Equals(newValue)) {
change();
OnPropertyChanged(name);
}
}
private string m_Title;
public string Title {
get { return m_Title; }
set {ChangeProperty(
new { Title }, //This is used to dynamically retrieve the property name and value
value, // new value
() => m_Title = value); //lambda to change the value
}
}
}
This is the best I could come up with. The runtime performance hit could be pretty high, but I haven't tested it.
A bit of explanation on the above solution. new { Title }
creates an anonymous object and due to projecttion (introduced in .NET 3.5) the newly created object has a single property called Title
and the value which is the value of Title
property of the original object.
GetPropertyNameAndValue
is the function that does all the interesting work - it retrieves the name and the value of the property out of the anonymous object. ChangeProperty
then performs equality check and invokes the lambda that actually changes the property and also calls NotifyPropertyChanged
.
Alternatively you could just do a snippet like so:
<?xml version="1.0" encoding="utf-8" ?>
<CodeSnippets xmlns="http://schemas.microsoft.com/VisualStudio/2005/CodeSnippet">
<CodeSnippet Format="1.0.0">
<Header>
<Title>propfullinotify</Title>
<Shortcut>propfullinotify</Shortcut>
<Description>Code snippet for property and backing field with INotifyPropertyChanged</Description>
<Author>Microsoft Corporation</Author>
<SnippetTypes>
<SnippetType>Expansion</SnippetType>
</SnippetTypes>
</Header>
<Snippet>
<Declarations>
<Literal>
<ID>type</ID>
<ToolTip>Property type</ToolTip>
<Default>int</Default>
</Literal>
<Literal>
<ID>property</ID>
<ToolTip>Property name</ToolTip>
<Default>MyProperty</Default>
</Literal>
<Literal>
<ID>field</ID>
<ToolTip>The variable backing this property</ToolTip>
<Default>myVar</Default>
</Literal>
</Declarations>
<Code Language="csharp">
<![CDATA[private $type$ $field$;
public $type$ $property$
{
get { return $field$;}
set {
if ($field$ != value)
{
$field$ = value;
if (PropertyChanged != null) PropertyChanged(this, new PropertyChangedEventArgs("$property$"));
}
}
}
$end$]]>
</Code>
</Snippet>
</CodeSnippet>
</CodeSnippets>