While combining EF5 with WPF MVVM, I noticed that changes to individual properties within my bound DataContext weren’t updating the UI.
This was of course because the the actual DataContext itself isn’t changing, but only the POCO Properties housed within in. However, each of the POCO Properties don’t individually raise an INotifyPropertyChanged event.
In order to implement this, one must modify the T4 Template provided as part of the EF 5.x DbContext Generator, to insert the extra lines which add the relevant code to Implement the Interface, and raise the INotifiyPropertyChanged Event.
This is performed by making the following modifications to the T4 Template;
(Note, I work in vb.net here, the code will be different for a c'# implementation!)
- Open you’re .tt file
- Find the Section which loops through all of the Complex Types in your model, which begins with the line “For Each loopComplex As ComplexType…”.
- Below the Line saying “Partial <#=Accessibility.ForType(complex)#> Class <#=code.Escape(complex)#>”, add the following two lines of code;
Implements INotifyPropertyChanged
Public Event PropertyChanged(sender As Object, e As System.ComponentModel.PropertyChangedEventArgs) Implements System.ComponentModel.INotifyPropertyChanged.PropertyChanged
This Implements the INotifiyPropertyChanged Interface, and adds the Public Events to each of the POCO’s for your Complex Types.
- Find the Write Header Sub, which starts with “Public Sub WriteHeader(ByVal fileManager As EntityFrameworkTemplateFileManager)”
- Below the “<#” and the line saying “fileManager.StartHeader()”, add the following line of code;
Imports System.ComponentModel
This adds a reference to “System.ComponentModel” , which is where INotifiyPropertyChanged lives.
- Find the AnyProperty Function, which starts with “Public Function AnyProperty(accessibility As String, type As String….”
- Replace the whole function with the following code;
Public Function AnyProperty(accessibility As String, type As String, name As String, getterAccessibility As String, setterAccessibility As String, defaultValue As String)
Return String.Format( _
CultureInfo.InvariantCulture, _
"{6} Private _{0} As {1}{2}{6}" & _
" {3} Property {0} As {1}{6}" & _
" {4}Get{6}" & _
" Return _{0}{6}" & _
" End Get{6}" & _
" {5}Set(ByVal value As {1}){6}" & _
" _{0} = value{6}" & _
" RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(""{0}"")){6}" & _
" End Set{6}" & _
" End Property", _
name, _
type, _
defaultValue, _
accessibility, _
getterAccessibility, _
setterAccessibility, _
Environment.NewLine)
End Function
This enforces that all Properties are created with their full Getter’s and Setter’s, and adds the code to raise the PropertyChanged Event<
- Find the “EntityClassOpening” Function, which starts with the Line “Public Function EntityClassOpening(entity As EntityType) As String”
- Replace the entire Function with the following Code;
Public Function EntityClassOpening(entity As EntityType) As String
Return String.Format( _
CultureInfo.InvariantCulture, _
"Partial {0} {1}Class {2}{3}{4}{5}{4}{6}", _
Accessibility.ForType(entity), _
_code.SpaceAfter(_code.MustInheritOption(entity)), _
_code.Escape(entity), _
_code.StringBefore(Environment.NewLine & " Inherits ", _typeMapper.GetTypeName(entity.BaseType)), _
Environment.NewLine, _
"Implements INotifyPropertyChanged", _
"Public Event PropertyChanged(sender As Object, e As System.ComponentModel.PropertyChangedEventArgs) Implements System.ComponentModel.INotifyPropertyChanged.PropertyChanged")
End Function
This adds the Implementation and Public Event for the INotifyPropertyChanged Interface
- Save your template, you may need to open your Model and save this also. Finall build your project, and you should have some fully declared Properties along with the INotifiyPropertyChanged code!
I hope this helps!