Friday, September 28, 2007
« Rebutting some questions about CSLA .NET... | Main | Using CSLA .NET 3.0 ebook available (and... »

It is a reasonably well-known fact that WPF misuses the Equals() method in the data binding implementation.

If you set a DataContext to an object, then set it to another object that is logically equal to the first, but which has different data, WFP gladly ignores the new object's data:

form.DataContext = A;
B = A.Clone();
B.Value = "new value";
form.DataContext = B;

Assuming A and B retain logical equality even though Value has changed, this code results in the UI not showing the new value. Apparently the reasoning is that if the objects are equal, then there's no need to update any data through data binding.

Of course this totally confuses ReferenceEquals() with Equals(), and the result is that objects used by WFP can no longer have logical equality. They can only have reference equality.

(or, arguably, WPF forces 100% property-level equality across objects, so equality can extend to two different instances as long as they have absolutely no different property values - which seems entirely useless)

In .NET 3.0 I had a solution, at least in CslaDataProvider. The solution was to temporarily set the DataContext to null, then to the new object. The result was that the faulty (imo anyway) equality comparison was defeated.

Unfortunately, it appears that .NET 3.5 may have "fixed a bug" that prevents this from working. The result is that it appears there is NO WAY TO REFRESH DATA when fields of an object change, but the object's logical identity remains the same.

I'm not yet sure of a final solution. The current situation is very bad, because you can either use WPF or you can have logical equality between objects - but not both.

It might be the case that people who need logical equality will have to implement their own parallel Equals() concept - ignoring the standard one built into .NET. That's a really poor solution, but if Microsoft isn't going to use their own framework responsibly then we're kind of stuck. Of course operators become an issue then, since operator overloading is related to Equals() as well. I suppose you could break that relationship, but then you'd get really odd stuff like this:

x = y is true

x.Equals(y) is false

But if WPF forces Equals() to be ReferenceEquals() instead of actual equality, then we come back to being stuck.

I love WPF - it is really cool. But this particular issue is a real problem. Apparently one without a real solution.

WPF

Friday, September 28, 2007 1:09:45 PM (Central Standard Time, UTC-06:00)
Rocky

Your situation sounds very familiar. I'm going to go way back to .Net 1.1, but it may have some merit. I was working on a Windows Forms project that used a variety of inherited forms and we had a very similar issue. We could not replace one object with another of the same type and have it report to the form properly.

If I remember correctly, part of the answer was to create a brand new DataContext object every time a form was created. Something like this:

DataContext dc = new DataContext();
form.DataContext = dc;
... [carry on with normal stuff]

It also had to be added very early in the form's creation, like in the HandleCreated event. I don't have the code handy, but you get my drift.

Have you tried anything like this?
Friday, September 28, 2007 1:36:20 PM (Central Standard Time, UTC-06:00)
Rocky - make 'em DependencyProperty and use 2way binding mode?
Sunday, September 30, 2007 11:03:43 AM (Central Standard Time, UTC-06:00)
Perhaps call form.ClearValue(FrameworkElement.DataContextProperty); and then try setting it to the logically equivalent object. That might work.
Wednesday, October 03, 2007 2:54:38 PM (Central Standard Time, UTC-06:00)
On further research I'm no longer certain it is the equality issue I'm facing in this particular case. Somehow the display is always one object behind.

As in:
It displays the object's data.
Then I edit the data and tell the UI to refresh. Nothing happens.
Then I edit the data and tell the UI to refresh. It displays the FIRST edits.
Etc.

I think the DataProvider is actually refreshing the data correctly, but the UI doesn't rebind to the DataProvider when i think it does. Nor is it clear how you'd force the UI to rebind to the DataProvider.
Wednesday, November 07, 2007 7:28:11 PM (Central Standard Time, UTC-06:00)
This sounds like a serious barrier to using CSLA under WPF, or is there something I'm missing? Is this not something that can be addressed through the use of IdentityConverter?
Paul Somers
Thursday, November 08, 2007 1:56:39 AM (Central Standard Time, UTC-06:00)
The issue is not CSLA-specific. Anyone using any object or data model that uses logical equivalence will encounter this problem. WPF closed off an entire interpretation of equivalence - and for no good reason I can find (because they could have used ReferenceEquals() to get what they wanted without f*cking with the rest of us).

But you are correct, it does impact CSLA. By default CSLA employs logical equivalence, because that works best for a lot of business scenarios. In CSLA 3.5 I will probably make logical equivalence optional, with the default being off. A breaking change, but you can't fight city hall...
Comments are closed.