OnPropertyChanged and maintaining a list of Dirty Properties

OnPropertyChanged and maintaining a list of Dirty Properties

Old forum URL: forums.lhotka.net/forums/t/11627.aspx

mtavares posted on Friday, October 05, 2012

In CSLA 3.8 I was maintaining a list of dirty properties by overriding the OnPropertyChanged event and adding the propertyname to an internal list of strings if it didn't already exist. Then I would clear that list in an override of MarkOld.  This worked without any issue in 3.8.

But now in 4.3 the OnPropertyChanged event seems to be working differently with the new Rules system.  In 3.8 I would change a property, and I would get a single OnPropertyChanged event thrown for that property.  But in 4.2 it is also throwing the OnPropertyChanged for each dependent property of the property I changed. As a result, my dirty properties list contains a bunch of properties in it that aren't actually dirty because they were never changed.

Further, there are 2 OnPropertyChanged methods, one with a string parameter and one with a propertyinfo parameter. I've tried both of them and while the string parameter method would be thrown for the changed property and all it's dependent properties, the propertyinfo parameter method wasn't being thrown at all.

So my question is, what should I now be doing to keep track of a dirty properties list in 4.3? Should I be using another method altogether?

Here is my code in my base class right now that is being thrown for the changed property and its dependencies:

    Public Shared ReadOnly DirtyPropertiesProperty As PropertyInfo(Of Collection(Of String)) = RegisterProperty(Of Collection(Of String))(Function(obj As MyBusinessBase(Of T)) obj.DirtyProperties, "Dirty Properties"New Collection(Of String))
    ''' <summary>
    ''' A collection of the properties that have been changed
    ''' </summary>
    Public Property DirtyProperties() As Collection(Of String)
            Return GetProperty(DirtyPropertiesProperty)
        End Get
        Set(ByVal value As Collection(Of String))
            SetProperty(DirtyPropertiesProperty, value)
        End Set
    End Property

    Protected Overrides Sub OnPropertyChanged(ByVal propertyName As String)
        ' Add the property to the list of dirty properties
        If Not ReadProperty(DirtyPropertiesProperty).Contains(propertyName) Then
        End If
    End Sub
    Protected Overrides Sub MarkOld()
        ' clear all dirty properties
    End Sub

Any help would be greatly appreciated.

JonnyBee replied on Friday, October 05, 2012

Override PropertyHasChanged insted of OnPropertyChanged.

OnPropertyChanged is just to signal that a property may have changed (or staus has changed) so the UI can refresh its value and status.
PropertyHasChanged is called once per property that is changed by yhe user.

However - you may have rules that update other fields (lookup rules etc) so for managed properties you can also ask the FieldManager of the status for the backing field. The Rule system will now also mark updated managed properties (from AddOutValue) as Dirty.   

You may also take a look at the extensions for backing fields that can check the old/new value to determine if the field is dirty. Code is available on http://cslacontrib.codeplex.com 

If you are using WIndowsForms then make sure to set the proper CslaPropertyChangedMode. The default mode was changed for CSLA 4.x to be Xaml.

mtavares replied on Friday, October 05, 2012

Thanks Jonny,

I never knew about the IsFieldDirty method on the FieldManager.  And using the PropertyHasChanged override worked as well. Thanks again.


jkellywilkerson replied on Wednesday, July 10, 2013

I converted the above into C#, but it doesn't want to compile. Are there changes available in 3.8 that aren't in 3.7 that would keep it from compiling?

    Public Shared ReadOnly DirtyPropertiesProperty As PropertyInfo(Of Collection(Of String)) = RegisterProperty(Of Collection(Of String))(Function(obj As MyBusinessBase(Of T)) obj.DirtyProperties, "Dirty Properties"New Collection(Of String))

public static readonly PropertyInfo<List<string>> DirtyPropertiesProperty = RegisterProperty<List<string>>((BusinessBase<T> obj) => obj.DirtyProperties, "Dirty Properties", new List<string>());

Also tried:
public static readonly PropertyInfo<List<string>> DirtyPropertiesProperty = RegisterProperty<List<string>>(Expression<Func<T, object>> T.DirtyProperties, "Dirty Properties", new List<string>(), RelationshipTypes.LazyLoad);

I get the "Invalid expression term 'object'" error on compile.

Thanks in advance for any light that can be shed on this.


JonnyBee replied on Wednesday, July 10, 2013

First - you should nor use the basic List<> for a registered property as this is not serializable by the new MobileSerializer (or in SL or WP). You may use the MobileList<> class or create your own business list class. 

This code works in C#:

    public static readonly PropertyInfo<MobileList<string>> DirtyPropertiesProperty = 
      RegisterProperty<MobileList<string>>(c => c.DirtyProperties, "Dirty Properties"new MobileList<string>(), RelationshipTypes.LazyLoad);
    public MobileList<string> DirtyProperties
      get { return GetProperty(DirtyPropertiesProperty);  }

And in VB.NET:
Public Shared ReadOnly DirtyPropertiesProperty As PropertyInfo(Of MobileList(Of String)) = _
RegisterProperty(Of MobileList(Of String))(Function(c) c.DirtyProperties, "Dirty Properties", New MobileList(Of String)(), RelationshipTypes.LazyLoad) Public ReadOnly Property DirtyProperties() As MobileList(Of String) Get Return GetProperty(DirtyPropertiesProperty) End Get End Property

Copyright (c) Marimer LLC