-
Notifications
You must be signed in to change notification settings - Fork 226
How to implement OnPropertyChanged
This guide shows how to add INotifyPropertyChanged support to generated POCO classes. Three of the four steps are ordinary Database.tt settings; the last edits one line of the property template.
Steps 1 to 3 live in Database.tt and survive every upgrade. Step 4 changes how every property is emitted, which means editing the property template inside EF.Reverse.POCO.v4.ttinclude; that file is replaced on upgrade, so keep the edit as a patch and reapply it.
If you only need OnPropertyChanged for specific scenarios, use the partial modifier and implement the logic in a separate file without touching the generator.
Settings.UpdateTable = delegate(Table table)
{
table.BaseClasses = " : INotifyPropertyChanged";
};Settings.AdditionalNamespaces = new List<string>
{
"System.ComponentModel",
"System.Runtime.CompilerServices"
};In Database.tt, use WriteInsideClassBody:
Settings.WriteInsideClassBody = delegate(Table t)
{
return
" public event PropertyChangedEventHandler PropertyChanged;" + Environment.NewLine +
" protected virtual void OnPropertyChanged([CallerMemberName] string name = null)" + Environment.NewLine +
" {" + Environment.NewLine +
" PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));" + Environment.NewLine +
" }" + Environment.NewLine;
};This step requires editing the Mustache property template inside EF.Reverse.POCO.v4.ttinclude.
Warning:
EF.Reverse.POCO.v4.ttincludeis replaced when you upgrade the generator, so keep this edit as a patch and reapply it afterwards.
In the property template, find the line that generates properties:
public {{#if OverrideModifier}}override {{/if}}{{WrapIfNullable}} {{NameHumanCase}}
Replace it with a backing field + property with change notification:
private {{WrapIfNullable}} _{{NameHumanCase}};{{#newline}}
public {{#if OverrideModifier}}override {{/if}}{{WrapIfNullable}} {{NameHumanCase}} { get { return _{{NameHumanCase}}; } {{PrivateSetterForComputedColumns}}set { if(value != _{{NameHumanCase}}) { _{{NameHumanCase}} = value; OnPropertyChanged(); } } }{{PropertyInitialisers}}{{InlineComments}}{{#newline}}Generated classes will look like:
public partial class Order : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string name = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
}
private int _orderId;
public int OrderId
{
get { return _orderId; }
set { if (value != _orderId) { _orderId = value; OnPropertyChanged(); } }
}
private string _customerName;
public string CustomerName
{
get { return _customerName; }
set { if (value != _customerName) { _customerName = value; OnPropertyChanged(); } }
}
}- Home
- Compared with the Microsoft scaffolder
- Connection strings
- JetBrains Rider
- Upgrading from v3 to v4
- Saving .tt does nothing
- Settings A-Z - every setting, with a page each
- Common Settings Types Explained
- Settings Callbacks
- Settings runtime values and helpers
- Filtering
- Full Control Over the Generated Code
- Enum Generation from Table Data
- Owned Entities
- JSON column support
- Global Query Filters
- Extended Property Names Feature
- Partial Properties
- File-Scoped Namespaces
- Data Annotations
- Spatial Types
- HierarchyId
- RowVersion and TimeStamp columns
- Lazy Loading
- Stored proc result sets