Is there a way to attach a broken rule to more than one property?

Is there a way to attach a broken rule to more than one property?

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


marthac posted on Tuesday, March 01, 2011

I've tried to use the AddWarningResult function that takes a property as the first parameter, but the broken rule only appears on the last property, not all of them.

Any help with this issue would be greatly appreciated.

Thanks. :)

ajj3085 replied on Tuesday, March 01, 2011

Did you try adding the other properties to the affected properties list?  I'm not sure but that might do it.

I''m fairly certain that the reason its not showing is that no propery changed event is being raised for the other properties; I think affected properties will do that however.

marthac replied on Wednesday, March 02, 2011

I did that. Here is my original post re: this problem. I posted this question again because I got no response to that post. I've copied the text here. Please read below.

I appreciate any help I could get with this. Thanks.

http://forums.lhotka.net/forums/t/10107.aspx

I am trying to write a rule that compares 4 properties and adds a warning result to all 4 properties when some condition exists.

In the ctor I am adding all properties to the InputProperties and adding the non-primary properties to the AffectedProperties like so: 

public UsiUniqueClient(IPropertyInfo lnameProperty, IPropertyInfo fnameProperty, IPropertyInfo ssnProperty, IPropertyInfo bdateProperty)
: base(lnameProperty)
{
 if (InputProperties == null)
 {
  InputProperties = new List<IPropertyInfo>();
 }
 InputProperties.Add(lnameProperty);//primary property
 InputProperties.Add(fnameProperty);
 InputProperties.Add(ssnProperty);
 InputProperties.Add(bdateProperty);
 AffectedProperties.Add(fnameProperty);
 AffectedProperties.Add(ssnProperty);
 AffectedProperties.Add(bdateProperty);
}


In the Execute function when the condition exists, I'm interating thru the InputProperties and calling context.AddWarningResult() for each property

int property, properties = context.Rule.InputProperties.Count;
for (property = 0; property < properties; property++)
{
 context.AddWarningResult(context.Rule.InputProperties[property], "Test warning");
 System.Diagnostics.Debug.WriteLine("Warning attached to " + context.Rule.InputProperties[property].Name);
}

It is only attaching the broken rule to the last property.

How do I get the broken rule to show up on all properties?

 

Charleh replied on Wednesday, March 02, 2011

I was just about to post with the same issue - I don't know if this is intentional or a bug, but I've ended up just adding multiple instances of the same rule - one for each property - it does mean the rule is running many times though!

Anyone got any ideas?

Curelom replied on Wednesday, March 02, 2011

I've never been able to get the affected properties to work myself either.

Charleh replied on Friday, March 04, 2011

My solution is to add multiple identical rules to multiple properties - something like this:

BusinessRules.Add(new CheckMultiplePropertiesRule(property1, new List<IPropertyInfo>() { property2, property3 });

BusinessRules.Add(new CheckMultiplePropertiesRule(property2, new List<IPropertyInfo>() { property1, property3 });

BusinessRules.Add(new CheckMultiplePropertiesRule(property3, new List<IPropertyInfo>() { property1, property2 });

The implementation of the CheckMultipleProperties rule has to do some extra work to check the primary property and add the broken rule to that depending on which property the primary is. At least then you don't need multiple rule implementations - something like

private class CheckMultiplePropertiesRule : BusinessRule
{
 protected override void Execute(RuleContext context)
        {
         BusinessObject obj = (BusinessObject)context.Target;
  if(obj.property1 + obj.property2, + obj.property3 > 0)  
  {
   context.AddErrorResult(PrimaryProperty, "Oh dear"); 
  }
 }

 public CheckMultiplePropertiesRule(IPropertyInfo primaryProperty, List<IPropertyInfo> affectedProperties)
  : base(primaryProperty)
 { 
  AffectedProperties.AddRange(affectedProperties); 
 }
}

marthac replied on Friday, March 04, 2011

Yes but it is still only attaching the broken rule to the primary property.

And I would have to jump thru hoops to figure out what propery was what since I need to pass the properties to a Command object in a certain order. And to have the same rule execute for all 4 properties means it would execute the cmd obj 4 times.

My rule is an async rule BTW, not sure if that makes a difference.

RockfordLhotka replied on Sunday, March 06, 2011

This does appear to be a bug, as I am unable to get it to work as expected either. I'll add it to the bug list.

Charleh replied on Tuesday, March 08, 2011

Hi Rocky,

Not sure if this one is related also but... I have a per object rule which is firing to add some out values to the context.

When these values are modified, the UI for my application does not get updated (it appears no propertychanged notification is being raised to the UI)

This also happens if I attach the rule to a property and use BusinessRules.CheckRules(MyPropertyInfo) from the PropertyChanged or ChildChanged event, but it works correctly if the property itself actually raises the change

Charleh replied on Friday, March 11, 2011

I've had a look at the CSLA4 source and found that it does not appear to raise a propertychanged notification for affected properties when 'checkrules' is called on it's own without a property change triggering it

It looks like PropertyHasChanged raises the change event on behalf of the affected properties - but the checkrule affected properties on their own don't get the notification

Going to hunt for a fix - this will sort quite a few of my rules issues

Charleh replied on Friday, March 11, 2011

Ok for now I've modified IHostRules so that the AllRulesComplete method takes an enumerable list of string - I had to do this as it seemed the easiest way to get it working when affectedProperties are handled as a List<string>

In IHostRules.cs:

 void AllRulesComplete(IEnumerable<string> affectedProperties);

Then I've modified BusinessBase and ReadOnlyBase so that their AllRulesComplete implementation raise a property changed event for each affected property

In BusinessBase.cs:

void Rules.IHostRules.AllRulesComplete(IEnumerable<string> affectedProperties)

{

foreach (string prop in affectedProperties)

OnPropertyChanged(prop);

OnValidationComplete();

}

Then at the end of each CheckRules method - I take the distinct list of affected properties and pass it in the AllRulesComplete call

In BusinessRules.cs:

if(!RunningRules && !RunningAsyncRules)

_target.AllRulesComplete(affectedProperties.Distinct().ToList());

This appears to work - the only issue I can see is that some of the properties may have already had a property changed notification due to them being the primary property so I don't know what performance will be like. I'll give it a test on one of my projects

Copyright (c) Marimer LLC