Field not marked as dirty after calling PropertyHasChanged

Field not marked as dirty after calling PropertyHasChanged

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


kreid posted on Wednesday, October 09, 2013

I have a property that required some custom behaviour in the setter:

I need to set another property bases on the new value, and delay rule checking until both properties are set. NB: all rules are triggered by PrimaryContactId, not PrimaryContact,

Here is my code:

 public static readonly PropertyInfo PrimaryContactIdProperty = RegisterProperty(c => c.PrimaryContactId);
        public int PrimaryContactId
        {
            get { return GetProperty(PrimaryContactIdProperty); }
        }

        public static readonly PropertyInfo PrimaryContactProperty = RegisterProperty(c => c.PrimaryContact, RelationshipTypes.Child | RelationshipTypes.LazyLoad);
        public IContact PrimaryContact
        {
            get
            {
                if (!FieldManager.FieldExists(PrimaryContactProperty))
                {
                    LoadProperty(PrimaryContactProperty, ContactLoader.Get(this.PrimaryContactId));
                    OnPropertyChanged(PrimaryContactProperty);
                }
                return GetProperty(PrimaryContactProperty);
            }
            set
            {
                CanWriteProperty(PrimaryContactIdProperty, true); // Execute any authorization rules on PrimaryContactId
OnPropertyChanging(PrimaryContactIdProperty); LoadProperty(PrimaryContactIdProperty, value != null ? value.Id : -1); LoadProperty(PrimaryContactProperty, value); PropertyHasChanged(PrimaryContactIdProperty); // Execute any property rules on PrimaryContactId } }

This results in my Business object being marked as dirty, but the PrimaryContactIdProperty itself is not marker as dirty, so it isn't updated.

Lookig through the source I see that "FieldManager.SetFieldData<P>(propertyInfo, newValue);" is used by SetProperty to mark updated fields as dirty. Unfortunately thes is an internal method :(.

What can I do?

JonnyBee replied on Wednesday, October 09, 2013

Change your setter code to:

            set
            {
                CanWriteProperty(PrimaryContactIdProperty, true); // Execute any authorization rules on PrimaryContactId
                OnPropertyChanging(PrimaryContactIdProperty);
                LoadProperty(PrimaryContactProperty, value);
                SetProperty(PrimaryContactIdProperty, value != null ? value.Id : -1);
            }

kreid replied on Thursday, October 10, 2013

This is logical, and a correct solution at the moment; but what if I need to assign some rules to PrimaryContact in future? I will need to use load property for both properties. This is my concern because I don't know if there is a solution, other than NOT assigning any rules to PrimaryContact. The problem is that future developers may not know this. So I am trying to come up with a foolproof pattern.

JonnyBee replied on Thursday, October 10, 2013

In general terms - my coding preference is to keep ALL properties as simple get/set and some extra code for lazy loaded properties.

So in your case - the problem is that your rules is attached to a property that is NOT the one set by the user. The user actually sets the PrimaryContact property - and I would rather have a rule that then sets the PrimaryContactId and runs the other rules.

So I believe all rules that need to run should have PrimaryContact as the PrimaryProperty.
Also remember that a rule may set an error or warning on another property than the PrimaryProperty.

Copyright (c) Marimer LLC