Reputation: 11617
after reading this article, a have the following code in my PersonViewModel
class:
public Jurisdiction CountryResidence
{
get
{
return Model.CountryResidence;
}
set
{
if (Model.CountryResidence == value)
return;
else
{
Model.CountryResidence = value;
base.OnPropertyChanged("CountryResidence");
}
}
}
public Jurisdiction CountryBirth
{
get
{
return Model.CountryBirth;
}
set
{
if (Model.CountryBirth == value)
return;
else
{
Model.CountryBirth = value;
base.OnPropertyChanged("CountryBirth");
}
}
}
I also have CountryDomiciled
, CountryPassport
and LegalJurisdiction
, all with the same format. Similarly, I have lots of String
properties, all of which share their format.
This results in lots of samey code! However, I can't work out how to make this more concise.
Is there a better way to generate these properties that keeps them strongly typed?
Upvotes: 8
Views: 4420
Reputation: 34218
UPDATE: NotifyPropertyWeaver is deprecated and continues its life as PropertyChanged.Fody. This is an absolute super cool way to solves this issue. It is a compile time only solution.
Here's something that will save you code and trouble: NotifyPropertyWeaver
Using the above, you can implement your properties without any INotifyPropertyChanged
related code, and a build step will handle the wiring up for you.
It's a simple project include (also available via Nuget) that will automatically inject the OnPropertyChanged
callbacks into the properties of any class that implements INotifyPropertyChanged
. It does it at compile time (so no runtime hit) and your code can just have auto-implemented properties (except in your case, where you're using a separate backing object).
It even includes the value equality check, so it covers the full logic. I haven't tested it with manually-implemented properties, but worth checking out.
EDIT: I have tested it now, and it works fine: a manually implemented property will "just work."
Upvotes: 4
Reputation: 33940
To get a "strong-typed" reference to the property name (which is required to enable refactoring), you can use expressions. Put the following method, perhaps in a base class for your viewmodels:
protected void RaisePropertyChanged<T>(Expression<Func<T>> property)
{
var handler = PropertyChanged;
if (handler == null) return;
var propertyName = NotifyPropertyChangedHelper.GetPropertyNameFromExpression(property);
handler(sender, new PropertyChangedEventArgs(propertyName));
}
In your viewmodels, you'll then be able to do the following:
public Jurisdiction CountryResidence
{
get { return Model.CountryResidence; }
set
{
if (Model.CountryResidence == value)
return;
Model.CountryResidence = value;
OnPropertyChanged(() => CountryResidence);
}
}
Now, refactoring property names are automatically picked up since the reference is against the actual property.
This solves the pain point of hardcoding property names, though it still requires the 4-5 lines of boilerplate code. Aspect-oriented approaches like notifypropertyweaver and PostSharp really removes all manual coding in the viewmodels.
Upvotes: 1
Reputation: 236278
I use snippet for Visual Studio, which generates property with backing storage and event raising for me. Simply create xml file with name propchanged
(or other name, if you wish) and following content:
<?xml version="1.0" encoding="utf-8" ?>
<CodeSnippets xmlns="http://schemas.microsoft.com/VisualStudio/2005/CodeSnippet">
<CodeSnippet Format="1.0.0">
<Header>
<Title>propchanged</Title>
<Shortcut>propchanged</Shortcut>
<Description>Code snippet for property (with call to OnPropertyChanged) and backing field</Description>
<Author>lazyberezovsky</Author>
<SnippetTypes>
<SnippetType>Expansion</SnippetType>
</SnippetTypes>
</Header>
<Snippet>
<Declarations>
<Literal>
<ID>type</ID>
<ToolTip>Property type</ToolTip>
<Default>string</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)
return;
$field$ = value;
OnPropertyChanged("$property$");
}
}
$end$]]>
</Code>
</Snippet>
</CodeSnippet>
</CodeSnippets>
And put it to folder C:\Users\YourName\Documents\Visual Studio 2010\Code Snippets\Visual C#\My Code Snippets\
.
Next, I inherit my ViewModels from some base ViewModel, which implements INotifyPropertyChanged
inteface and provides protected method OnPropertyChanged
for generating `PropertyChanged' event.
public class ViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propertyName);
}
}
Now when you type propchanged
in Visual Studio, it will ask you for property type and name, and generate code for you.
public class PersonViewModel : ViewModel
{
// type here 'propchanged' (or other shortcut assigned for snippet)
}
UPDATE:
Another option is generating code by AOP framework like PostSharp. In this case code will be generated and added during compilation (thus your classes will stay clean). Here is example of implementing INotifyProperty changed via PostSharp attributes:
[Notify]
public class PersonViewModel
{
public Jurisdiction CountryResidence { get; set; }
public Jurisdiction CountryBirth { get; set; }
}
Upvotes: 11
Reputation: 21261
Not really what you're looking for, but as an aside you can save two lines per property by reversing your logic test:
public Jurisdiction CountryResidence
{
get
{
return Model.CountryResidence;
}
set
{
if (Model.CountryResidence != value)
{
Model.CountryResidence = value;
base.OnPropertyChanged("CountryResidence");
}
}
}
Upvotes: 2
Reputation: 132618
I don't know of any built-in way, but you could record a Macro that will generate the code for you. I find the easiest way to do that is to just start recording a macro, then create whatever you want using the keyboard only (you can find a list of handy keyboard shortcuts here )
For example, I have one that generates the public version of a property, so all I have to type is private string _someValue;
and hit my macro, and it will generate the public property along with the property change notification.
That said, keep in mind that it's perfectly valid in MVVM to expose the entire Model to the View for the sake of simplicity and convenience. So instead of exposing each of the Model's properties separately, you would simply create a single property for your Model object.
public Model SomeModel
{
get
{
return Model;
}
set
{
if (Model == value)
return;
else
{
Model= value;
base.OnPropertyChanged("SomeModel");
}
}
}
And bind to the model's properties like this:
<TextBox Text="{Binding SomeModel.SomeProperty}" />
Upvotes: 1
Reputation: 2938
Haven't you tried using Visual Studio code snippets such as prop
or propfull
? Just type it and press Tab key twice. Problem is propfull
snippet doesn't raise PropertyChanged event.
But actually there should be third party snippets for such task. Here's what I found: property snippet with INPC
Upvotes: 0