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?
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);
}
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.
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