Bug with PropertyStatus when bound to nullable type and it's initial value is null

Bug with PropertyStatus when bound to nullable type and it's initial value is null

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


Jaans posted on Wednesday, December 02, 2009

Hi Rocky

This took me ages to figure out but managed to pin it down some.

Business Object:
----------------------
I have a business object with an editable property of type DateTime? (nullable date time).

There is a validation rule on the property that evaluates to fail if the value is null when the BO is not new (!IsNew).

For these tests I just created dummy rule logic that always returns invalid for the sake of simplified testing.

User Interface:
---------------------
In the Silverlight UI there is a PropertyStatus control that is bound to this property.

Problem / Bug:
--------------------
I instantiate the UI container (Silverlight user control) and set the DataContext to a business object which has a value of null for the property in question.

The validation rules for this property results in a broken rule for this property.

The PropertyStatus control does not show the red circle to show that the property has a broken rule.

Other observations:
---------------------------
* I've verified that the business object's state - with regard to the broken rules - is correct.
Also, the same business object bound in a Windows Forms UI with a ErrorProvider control does indeed show the broken rule for the property.

* If the initial value is not null, the PropertyStatus control correctly shows the broken rule icon

* If the type of the property is changed to not be a nullable type (ie. DateTime) then the PropertyStatus control correctly shows the broken rule icon.
This is similar to the above bullet in the sense that the initial value won't be null either

* If the value of the property is set in the UI, then the PropertyStatus suddenly starts to show the broken validation rule again, even if the value goes back to null.

From that point onwards the control works. I even set a new business object instance to the DataContext and it worked as expected, but if I create a new instance of the User Control container (which implicitly creates a new instance of the PropertyStatus control) then the issue returns when the initial value for the property is null.

This was observed in CSLA Version 3.8.1,
I cannot confirm but it seems that the problem started with the updated property status control since 3.8 as I cannot recall this issue with 3.7 (but I cannot confirm).

Workaround:
-----------------
None - I have been unable to find a way to trick the propertystatus to work on the initials display.
(It's a particularly troubling issue for us because we dispose and recreate the UI Container for every business object instance)

I hope that helps define it a bit. If you need any more detail, please just let me know.

Jaans

RockfordLhotka replied on Thursday, December 03, 2009

Thank you, I'll add this to the bug list.

Jaans replied on Thursday, December 03, 2009

Great... thanks Rocky

Ps: Is it possible to link the post to the issue tracker bug?

Our client is a bit "anal" about the issue so I might need to get the fix from source code (SVN) before it gets integrated into a new release for CSLA 3.8.3 / 4.0.0? Depending of course when you are able to find some time to fix it :-)

Thanks again,
Jaans

RockfordLhotka replied on Thursday, December 03, 2009

http://www.lhotka.net/cslabugs/edit_bug.aspx?id=660

RockfordLhotka replied on Thursday, December 03, 2009

I am reasonably certain I won't have time to look at it until around
mid-month due to my travel and work schedule.

You might walk through the code in the debugger and see if you can identify
the specific point of failure - maybe a null reference exception or
something - which could speed up my ability to fix the issue.

Jaans replied on Thursday, December 03, 2009

No worries Rocky - I do appreciate that your time is limited, so I understand that you'll get to it when you can. Thanks for the rough timeline though.

I'll try and have a look and see what I can find. Maybe it's something easy.

Enjoy your time in Europe!

Jaans replied on Friday, December 04, 2009

Hi Rocky

I have some good news. I've tracked it down and have a proposed solution (that is a very simple fix).

I'll try and give you as much information as possible, but please let me know if anything is unclear.

Context:
--------
This is in the Silverlight\PropertyStatus.cs file

* SetSource() is "registered" as the PropertyChangedCallback for the PropertyProperty (DependencyProperty).

* SetSource() is also called in the Set property accessor defined on the PropertyStatus.Property property.


Issue:
------
* The following describes the a scenario that works correctly and as expected:
I bind PropertyStatus.Property to a business object property that is not a nullable type (e.g. int).
Set a new instance of the business object to the DataContext --> this causes the PropertyChangedCallback to fire for the PropertyProperty (which in turn calls the SetSource() method).

* The following shows an edge case where it doesn't work as expected:
I bind PropertyStatus.Property to a business object property that is a nullable type (e.g. DateTime?).
Set a new instance of the business object (that has a null value for the property in question) to the DataContext --> The PropertyChangedCallback does *not* fire and therefore does not call SetSource().

It would appear that the issue lies with Silverlight, not calling the property changed event when binding to a null value, but upon further investigation it makes sense that the PropertyChangedCallback doesn't fire.
I say this because technically the original default value for the property is null and upon binding the new value from the business object is also null. Technically the value didn't change and thus not PropertyChangedCallback being fired.
This is clearly an optimisation on the part of the DependencyProperty implementation.


Solution:
---------
It turns out that there is a very simple solution.
Essentially it involves specifying a default value for the dependency property such that when binding kicks in, that any value (including null) is different to the default value thus resulting in a property change occurring.
Such a default value is simply specifying a new object() for the PropertyMetadata constructor during the registration of a dependency property.


Code change:
------------

Original - Here is the dependency property declaration for the PropertyProperty:

///
/// Gets or sets the source business
/// property to which this control is bound.
///
public static readonly DependencyProperty PropertyProperty = DependencyProperty.Register(
"Property",
typeof (object),
typeof (PropertyStatus2),
new PropertyMetadata( ( o, e ) => ((PropertyStatus2)o).SetSource() ) );


Proposed change - Define a default value is unique such that any value being set will cause a property changed callback to fire.
Note: The change is to the PropertyMetadata constructor.

///
/// Gets or sets the source business
/// property to which this control is bound.
///
public static readonly DependencyProperty PropertyProperty = DependencyProperty.Register(
"Property",
typeof (object),
typeof (PropertyStatus2),
new PropertyMetadata( new object(), ( o, e ) => ((PropertyStatus2)o).SetSource() ) );

Obviously this is a propsed change that I hope this meets your approval and doesn't break something else I'm not aware of.

Regards,
Jaans

elizas replied on Friday, May 07, 2010

The nullable type can represent a normal or regular set of values for its value type including the null value.
 
    If we take an example of bool type, then Nullable<bool> can contain set of values like true or false or null.So, assigning null value to bool is useful when we are dealing with database in which the Boolean field may store value like true or false or it may be sometimes undefined.
 
Nullable Types are instances of System.Nullable struct.
 
Declaration:
A nullable type can be declared similar to normal variable but with ? modifier at the end of keyword.For example,
int? number = null;
Here ? denotes that the object is a Nullable object of that specific datatype(here it is int).
 
Alternative way of declaring Nullable type is,
Nullable<int> number = null;
 

Copyright (c) Marimer LLC