Data Access has been discontinued. Please refer to this page for more information.

How to: Implement INotifyPropertyChanging/ed Interface on DTOs (C#)

This article is relevant to entity models that utilize the deprecated Visual Studio integration of Telerik Data Access. The current documentation of the Data Access framework is available here.

This topic illustrates how to modify the code generation templates used by the Service Wizard, in order to automatically implement the INotifyPropertyChanging/ed interfaces for the generated C# Data Transfer Objects (DTOs).

This topic applies to C# only. For VB version, please refer to How to: Implement INotifyPropertyChanging/ed Interface on DTOs (VB).

To implement INotifyPropertyChanging/ed interfaces:

  1. Create a new folder named OpenAccessTemplates in the host project, as it is described in the How to: Customize Code Generation topic. The Service Wizard will start looking for code generation templates from the host project and then from the Telerik Data Access installation folder.
  2. Copy/Paste the entire <install-dir>/dsl2012/CodeGenerationTemplates/Dto/CSharp/Includes folder in the OpenAccessTemplates folder:

  3. Open the General.ttinclude template. The INotifyPropertyChanging/ed interfaces are in the System.ComponentModel namespace. By default that namespace is not included in the generated DTOs. The first step is to include it. Navigate to the GenerateNamespaces method (in the original version of the template, the beginning of the method should be located at line 165). Add the System.ComponentModel namespace like the code snippet below:

    this.WriteLine("using System.ComponentModel;");
    
  4. You need to modify the Specific.ttinclude template and add code for generation of the INotifyPropertyChanged/Changing events and methods that raise the events. Open the Specific.ttinclude template. The first step is to change the class signature so that it implements the INotifyPropertyChanged/Changing interfaces. Navigate to line 67 or find the following code:

    public partial class <#= this.nameService.GetDTOName(@class.Name) #> : 
        <#= this.nameService.DtoWithKeyInterfaceName #>
    

    Modify this line so it looks like this:

    public partial class <#= this.nameService.GetDTOName(@class.Name) #> : 
        <#= this.nameService.DtoWithKeyInterfaceName #>, 
            INotifyPropertyChanging, INotifyPropertyChanged
    
  5. Next, you need to modify the DtoKey property to use a private field (instead of auto-implemented property) and provide change notifications. Navigate to line 88-89 where is the generation of the DTO properties:

    [DataMember]
    public virtual string <#= this.nameService.DtoKeyPropertyName #> { get; set; }
    

    Modify the code above so it looks like this:

    [DataMember]
    public virtual string <#= this.nameService.DtoKeyPropertyName #>
    {
    get { return this._dtoKey; }
    set
        {
         if(<#= this.nameService.DtoKeyPropertyName #> == value)
          return;
         this.OnPropertyChanging("<#= this.nameService.DtoKeyPropertyName #>");
         this._dtoKey = value;
         this.OnPropertyChanged("<#= this.nameService.DtoKeyPropertyName #>");
        }
    }
    private string _dtoKey;
    
  6. Right below the code for DtoKey property generation, you should note the following method call (after the previous modifications, it should be located at line 104-106):

    <#+
       this.GenerateProperties(@class.Properties);
    #>
    

    You need to add code for generation of the INotifyPropertyChanged/Changing events and methods that raise the events. This part of the Specific.ttinclude template should look like:

    <#+
       this.GenerateProperties(@class.Properties);
    #>
    public event PropertyChangedEventHandler PropertyChanged;
    public event PropertyChangingEventHandler PropertyChanging;
    protected virtual void OnPropertyChanged(string info)
    {
    if(this.PropertyChanged != null)
     this.PropertyChanged(this, new PropertyChangedEventArgs(info));
    }
    protected virtual void OnPropertyChanging(string info)
    {
    if(this.PropertyChanging != null)
     this.PropertyChanging( this, new PropertyChangingEventArgs(info));
    }
    
  7. Navigate to the GenerateProperty(Telerik.OpenAccess.CodeGeneration.CodeProperty property) method. Find the following line:

    property.FieldName = string.Empty;
    

    And comment it:

    //property.FieldName = string.Empty;
    
  8. The final step is to modify the DTO properties to use private fields and provide change notifications. Navigate to the GenerateProperty(PropertyDetail details) method.

    private void GenerateProperty(PropertyDetail details)
    {
    //GenerateSummary(details.summary);
    if (!details.areModifiersCompatible)
    {
     this.WriteLine("//TODO: Please, resolve the following error: {0}", 
        details.propertyErrorMessage);
     this.Error(details.errorMessage);
    }   
    //Generates the DataMember attribute.
       this.WriteLine("[DataMember]");
    // generates the property signature
    this.Write(string.Format("{0} {1} {2}", details.modifiers, details.propertyType, 
        details.propertyName));
     if (details.useField)
     {
      this.WriteLine(string.Empty);
     }
     else
     {
      this.Write(" ");
     }
    #>{<#+
    // we always generate getters on the DTOs
    //if(details.hasGetter)
    //{  
    if (details.useField)
      this.WriteLine(string.Empty);
      this.Write(" ");
    #>get<#+
    if (details.useField)
    {
     this.WriteLine(string.Empty);
    #>
       {
           return this.<#= details.fieldName #>;
       }
    <#+    
    }
    else
    {
    #>;<#+
    }
    //}
    // we always generate setters on the DTOs
    //if(details.hasSetter)
    //{
    if (details.useField)
     this.Write(" ");
    #>set<#+
    if (details.useField)
    {
     this.WriteLine(string.Empty);
    #>
       {
           this.<#= details.fieldName #> = value;
       }
    <#+    
    }
    else
    {
    #>;<#+
     this.Write(" ");
    }
    //}
    #>}
    <#+
     if (details.useField)
    {
     // generates the field signature
     this.WriteLine(string.Format("{0} {1} {2} = {3};", details.fieldModifier, 
        details.propertyType, details.fieldName, details.initialValue));
     }
    this.WriteLine(string.Empty);
    }
    

    Modify it or replace it, so it looks like this:

    private void GenerateProperty(PropertyDetail details)
    {
    //GenerateSummary(details.summary);
    if (!details.areModifiersCompatible)
    {
     this.WriteLine("//TODO: Please, resolve the following error: {0}", 
        details.propertyErrorMessage);
     this.Error(details.errorMessage);
    }   
    //Generates the DataMember attribute.
       this.WriteLine("[DataMember]");
    // generates the property signature
    this.WriteLine(string.Format("{0} {1} {2}", details.modifiers, details.propertyType, 
        details.propertyName));
    #>
    {
       get
       {
           return this.<#= details.fieldName #>;
       }
       set
       {
          if( <#=details.propertyName#> == value )
              return;
    
          this.OnPropertyChanging("<#=details.propertyName#>");
          this.<#= details.fieldName #> = value;
          this.OnPropertyChanged("<#=details.propertyName#>");
       }
    }
    <#+
    // generates the field signature
    this.WriteLine(string.Format("{0} {1} {2};", details.fieldModifier, details.propertyType, 
        details.fieldName));
    this.WriteLine(string.Empty);
    }
    
  9. Save your templates and generate your WCF Service. Now all DTO classes from the Transport.cs file should implement the INotifyPropertyChanged/Changing interfaces.