I am observing what appears to be new/different behavior from WPF 3.0 to 3.5, and I'm wondering if anyone else has seen this.
In WPF 3.0, like Windows Forms, a PropertyChanged event causes all controls for the related data source (business object) to refresh. So changing a property causes all other properties of that object bound to the UI to refresh in the display.
In WPF 3.5 it appears that only the changed property's control is refreshed. Other controls on the form are not refreshed. This is a problem for validation error reporting, because it is also the case that the ValidatesOnErrors setting only causes revalidation when the display is refreshed.
Has anyone else seen this, or is it a quirk I'm running into in my project?
I have come across this same issue. To work around it, I've added a PropertyChanged method to the form that walks through the visual tree, grabs the binding expressions, then calls UpdateSource on the appropriate expressions. This hasn't been working perfectly, as I have a tab control, and walking the visual tree doesn't go through the controls on the unselected tabs. I also have to account for the different binding expressions for the different type of controls such as textboxes and Comboboxes.
public void ValidationControls(Visual myVisual) { for (int i = 0; i < VisualTreeHelper.GetChildrenCount(myVisual); i++) { // Retrieve child visual at specified index value. Visual childVisual = (Visual)VisualTreeHelper.GetChild(myVisual, i); // Do processing of the child visual object. if (childVisual is Control && ((Control)childVisual).Name != null) { Control ctl = (Control)childVisual; Console.WriteLine(ctl.Name); BindingExpression be = null; if (ctl is TextBox || ctl is ComboBox) { if (ctl is TextBox)be = ctl.GetBindingExpression(
TextBox.TextProperty); else if (ctl is ComboBox)be = ctl.GetBindingExpression(
ComboBox.SelectedValueProperty); if(be != null)be.UpdateSource();
}
}
// Enumerate children of the child visual object.ValidationControls(childVisual);
}
}
Good, at least I'm not making it up
I think I can solve it inside CSLA - but it means divergent behavior between data binding for Windows Forms and for WPF. Up to now I've been able to keep them consistent, so this is sad. But Microsoft has apparently decided to diverge their behavior, so I think we're stuck.
The solution I think might work (and I haven't dug into the code on this) is for SetProperty() (or more likely PropertyHasChanged()) to get back a list of changed properties from CheckRules(), and then call OnPropertyChanged() for each property in the list.
In other words, ValidationRules.CheckRules() could return an array of property names for each property that changed - or at least each property for which rules were checked. PropertyHasChanged() is running in the actual business object (in BusinessBase) and so it can raise PropertyChanged events.
In Windows Forms this would be very inefficient, since each of the PropertyChanged events would cause a refresh of the UI. But in WPF they are doing what Windows Forms probably should have done and only refreshing controls bound to changed properties. Raising multiple PropertyChanged events makes sense in WPF.
So then there needs to be a configuration switch so you could activate this new behavior. Perhaps Csla.ApplicationContext.PropertyChangedMode, which would be either Default or Xaml (assuming Silverlight follows the WPF model).
I think I'd make this PropertyChangedMode load from app.config, or be something you can set in code. In other words, it would be a read-write property.
Thoughts?
In talking to a member of the WPF team, it sounds like this is NOT a behavioral change from 3.0 to 3.5.
I imagine I never noticed the issue in 3.0 because I was using Csla.Wpf.Validator for validation error display, and it replicates the Windows Forms ErrorProvider behavior. Now in 3.5 I'm using the new validation behavior built-in to WPF and so am seeing the issue.
Ultimately the current WPF behavior is clearly the correct behavior, in that I'd expect only a changed property to be updated in the UI. The Windows Forms model never seemed right in that regard.
I'll work on adding the solution I proposed above to 3.5.1 and all will be well.
RockfordLhotka:Ultimately the current WPF behavior is clearly the correct behavior, in that I'd expect only a changed property to be updated in the UI. The Windows Forms model never seemed right in that regard.
Hot dog, your fix works.
Thank you
When a property changes, a PropertyChanged event for that
property must be raised.
If the property is a managed property and you use SetProperty(),
then CSLA raises the event for you.
If you implement the property in any other manner (so you don’t
call SetProperty()), then you must raise the PropertyChanged event for
that property. You do that by calling OnPropertyChanged().
In a WPF setting, you must set the PropertyChangedMode to
Xaml, or data binding simply won’t refresh correctly, because CSLA won’t
raise enough PropertyChanged events. In the older Windows Forms model you
wanted to minimize the number of PropertyChanged events raised, but in WPF you
need to explicitly raise an event for every changed property. The
PropertyChangedMode tells CSLA which model to use.
Rocky
I don’t have the full picture here.
Your VATAmount property is in a child of a collection? And you
have a property on the parent object that needs to recalculate?
This has been discussed in numerous threads – the answer
is that the parent object needs to handle the ListChanged event of the
collection and use that as a trigger to do the calculation.
Rocky
Copyright (c) Marimer LLC