BrokenRulesCollection.ListChanged...

BrokenRulesCollection.ListChanged...

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


kbcb posted on Thursday, May 24, 2007

Just a thought, but shouldn't changes to a child's BrokenRulesCollection raise PropertyChanged events on the child object so that parent lists can raise ListChanged events?

RockfordLhotka replied on Thursday, May 24, 2007

Almost always, when a rule is broken is is because a property changed, and so there's already a PropertyChanged event coming from the child.

If you explicitly call ValidationRules.CheckRules(), you might consider also calling OnUnknownPropertyChanged() to force the event to be raised.

You don't want duplicate events raised though, because data binding would do multiple UI refreshes then, and you could get performance issues...

Brian Criswell replied on Thursday, May 24, 2007

Changes to a chilg's BrokenRulesCollection usually occur because of a call to PropertyHasChanged, which raises a PropertyChanged event.  Are you changing the collection in some other circumstance?

kbcb replied on Thursday, May 24, 2007

Yes... I have a ValidationRule which validates an entire list. In our case, item2 might validating against item1, and because of an item validation dependency, item2 invokes a validation on item1 as well. If the BrokeRulesCollection of item1 changes, I would expect it to raise OnUnknownPropertyChanged in order to get the UI to update correctly with the error providers. However, because this isn't built into the framework, I have to check for it manually within the object by wiring to the object's BrokenRulesCollection.ListChanged event, and subsequently calling OnUnknownPropertyChanged within the handler.

RockfordLhotka replied on Friday, May 25, 2007

Object X should never validate object Y. Object X can ask object Y to validate itself, but X can't do the validation. To do so would break encapsulation.

If you edit a child object (Cx) in a collection, it may need to run some rule over all the children in the list (Cn). For each C in Cn your rule method should ask that specific C to validate itself - perhaps passing in key data to make the validation possible.

I say this, but I only do it in cases where the validation may change the state of each C. You can't have Cx changing the state of its peers (or any other object for that matter), but you can have Cx asking its peers to validate themselves.

To do this, you'll likely end up implementing a Friend/internal method in class C, so Cx can loop through and invoke this method on each C. Inside that method you will likely call CheckRules() in one form or another. And then you could call OnUnknownPropertyChanged().

As I said earlier, I don't want to raise such an event automatically, because then in the normal scenario you'd end up with duplicate events all the time, and data binding would double-refresh on every property change (or at least many property changes).

What I maybe could do, is to put a BrokenRulesChanged property on ValidationRules. This property would only return true if the last CheckRules() call change the list of broken rules. Without doing some research I don't know if I can do such a thing without performance ramifications, but it might be possible. Then your Friend/internal validation method could look like this:

Friend Sub PeerValidationRequest()
  ValidationRules.CheckRules("XYZ")
  If ValidationRules.BrokenRulesChanged Then
    OnUnknownPropertyChanged()
  End If
End Sub

I'll add this thread to the wish list as something to consider in the future.

(note to self: I think that BrokenRulesCollection could have an internal 'changed' property. CheckRules (before checking rules each time) would set that property to false, and the list changed overrides for set/remove/insert would set the property to true. Then ValidationRules would delegate to that property to implement the public read-only BrokenRulesChanged property.)

RockfordLhotka replied on Tuesday, November 27, 2007

I'm looking at this issue and thinking more about it.

I think a viable solution, that would be cheap and effective, would be for BrokenRulesCollection to have a "revision number". Any change (add/remove) to the list would change that number. Then you could write this:

Friend Sub PeerValidationRequest()
  Dim old As Integer = ValidationRules.GetBrokenRules().Revision
  ValidationRules.CheckRules("xyz")
  If old <> ValidationRules.GetBrokenRules().Revision Then
    OnUnknownPropertyChanged()
  End If
End Sub

This is less quirky and lower impact that what I'd suggested in that last post, and provides a workable solution to this issue from what I can see.

Copyright (c) Marimer LLC