PropertyHasChanged / MarkDirty

PropertyHasChanged / MarkDirty

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


SMILEMan posted on Tuesday, May 20, 2014

I'm using CSLA 4.5.501 from NuGet w/WPF.

In Rocky's eBook Creating Business Objects the MarkDirty Method says:
"By default this method not only effectively set IsSelfDirty to true, it also raises the PropertyChanged event with a property of string.Empty.  This tells the data bining to refresh the bindings on all the properties of the object, ensuring that the UI is up to date based on any changes that were committed to the object's state or metastate."

This is the behavior that I want, but when I change a text field on my model and step through in the debugger, only the Getters of the Affected properties are called.   Specifically I want a CSLA Property that accesses the metadata (IsDirty, IsValid, broken rules, etc.) to be updated in the UI when any of my read / write Properties are changed.

Has something changed since the book was written and if so, how do I get the behavior above?

Ray.

RockfordLhotka replied on Wednesday, May 21, 2014

The IsDirty, IsValid, and other metadata properties are marked as [Browsable(false)] and so they are ignored by data binding.

It is a bit of iffy design on Microsoft's part, because if we make them browsable then the UI designers in Visual Studio won't ignore them either so you'll have to manually remove them every time you let VS auto-create things like grid columns.

The PropertyInfo control in Csla.Xaml is designed to elevate all the metastate values about a property to be bindable. This turns out to be a better solution overall, at least for property-level metastate, because every property has numerous metastate values to which you might want to bind.

All that said, I _think_ we might have changed the browsable attribute in version 4.5 so at least some of the object level metastate properties are directly bindable. I was doing a bunch of stuff right before I had my heart events last year and I'm afraid my memory isn't as clear as I'd like from that time period...

SMILEMan replied on Thursday, May 22, 2014

I'm not sure that it's about the Browsable(false) attribute.   If my object has 10 properties and the user changes one that causes a 2nd to be changed (affected), what's happening when stepping through in debug is only the 2 property "get"s are being called rather than all 10.  One of my properties is a "traffic light" object status that I want to have set without specifically including it in my all my rules as an affected property (though if I had to I could try to make it a DataAnnotation type rule to simplify coding).  The code for my property is attached.   Any suggestions would be welcome.

RockfordLhotka replied on Thursday, May 22, 2014

The behavior of how CSLA raises PropertyChanged is different depending on whether you are in Windows Forms or XAML.

It sounds like the content in the book you reference relates to Windows Forms, and probably should be more clear (and/or corrected).

In Windows Forms when PropertyChanged is raised for a bound property the data binding infrastructure will refresh all bound properties. Raising PropertyChanged with a null or string.Empty property name also refreshes all bound properties. As a result CSLA is optimized to raise as few PropertyChanged events as possible, but always at least one. Raising lots of events just causes performance issues, but raising zero would make the UI not refresh.

In XAML (WPF, SL, WinRT) Microsoft changed the way data binding refreshes to work the way you'd expect - which is to say that properties refresh only if their specific PropertyChanged event is raised. In this context CSLA is optimized to raise PropertyChanged events as properties change, or are affected by rules.

If you have rules that affect a property (such as your traffic light) then that property should be an affected property in the rules so the CSLA infrastructure does the right thing for each data binding environment.

JonnyBee replied on Friday, May 23, 2014

Or just add this simple rule to you project and add one rule in your BO:

    public class NotifyChangedWhenInputChanged : Csla.Rules.BusinessRule
    {
        public NotifyChangedWhenInputChanged(IPropertyInfo primaryProperty, params IPropertyInfo[] inputProperties) : base(primaryProperty)
        {
            InputProperties = InputProperties ?? new List<IPropertyInfo>();
            InputProperties.AddRange(inputProperties);
        }
 
        protected override void Execute(RuleContext context) { }
    }
}

usage in BO:
BusinessRules.AddRule(new NotifyChangedWhenInputChanged(StatusProperty, Param1Property, Param2Property));

You can add as many properties as you like...

Copyright (c) Marimer LLC