CoerceValueCallback madness

341 views
Skip to first unread message

Bill Kempf

unread,
Mar 30, 2011, 9:15:41 AM3/30/11
to wpf-di...@googlegroups.com
I've got a NumericUpDown implementation done in WPF that's very similar to implementations you can find just about everywhere, including when in the "Extended WPF Toolkit" (http://wpftoolkit.codeplex.com). I have no idea if this project has any official connection to the actual WPF Toolkit and thus to Microsoft, but suffice it to say the issue I'm about to discuss is in nearly every NumericUpDown implementation I can find. Here's what you do to produce the problem.
 
Add a NumericUpDown to your window and set a Minimum (10) and Maximum (100) value, then bind the Value to a property on your ViewModel (or just do it in the codebehind to make the sample simple). Set a break point on your property's setter. Run the application and use the up button to increment the Value and show that your break point gets hit and that everything is working. Now, use the edit portion to manually set the value to something less than the Minimum (-1) and tab out of the control. Your break point will get hit, but note that the value being set is the value you entered in the control (-1). Continue running and note that the control actually shows the Minimum (10) value.
 
What's happening is that the Value DependencyProperty is using a CoerceValueCallback to ensure the values remain in range. However, what happens when you do this is FUBAR. When you call SetValue on the DependencyProperty this is roughly what happens:
 
1. Any BindingExpression sources are updated with the value.
2. The CoerceValueCallback (if present) is called to coerce the value.
3. The coerced value is used to set the actual DependencyValue property.
4. If (and only if) the value actually changed will any property changed callbacks/events be raised.
 
Due to (1) happening first, our bound data model gets the pre-coerced value. Due to (4) there's no hook left for us to ensure that our data model eventually gets the coerced value. This behavior is surprising, and devestating. If you search around on the Internet for this issue you'll find surprisingly little information considering how big of an issue this is. No workarounds can be found anywhere. However, the issue was entered on Connect (http://connect.microsoft.com/VisualStudio/feedback/details/489775/wpf-binding-expression-updates-source-before-coercevaluecallback-is-called), where Microsoft responded that this was "by design" with a very lame example meant to illustrate why the design exists.
 
I'm facing a very short deadline in which I've got to try and find a work around for this issue, unfortunately. I don't suppose anyone has any bright ideas here?

--
 Quidquid latine dictum sit, altum sonatur.
- Whatever is said in Latin sounds profound.

War is peace. Freedom is slavery.  Bugs are features.

Josh Smith

unread,
Mar 30, 2011, 12:52:11 PM3/30/11
to wpf-di...@googlegroups.com
I would use a value converter on the binding to coerce the value.

Josh

On Wednesday, March 30, 2011, Bill Kempf <wek...@gmail.com> wrote:
> I've got a NumericUpDown implementation done in WPF that's very similar to implementations you can find just about everywhere, including when in the "Extended WPF Toolkit" (http://wpftoolkit.codeplex.com). I have no idea if this project has any official connection to the actual WPF Toolkit and thus to Microsoft, but suffice it to say the issue I'm about to discuss is in nearly every NumericUpDown implementation I can find. Here's what you do to produce the problem.
>  Add a NumericUpDown to your window and set a Minimum (10) and Maximum (100) value, then bind the Value to a property on your ViewModel (or just do it in the codebehind to make the sample simple). Set a break point on your property's setter. Run the application and use the up button to increment the Value and show that your break point gets hit and that everything is working. Now, use the edit portion to manually set the value to something less than the Minimum (-1) and tab out of the control. Your break point will get hit, but note that the value being set is the value you entered in the control (-1). Continue running and note that the control actually shows the Minimum (10) value.
>  What's happening is that the Value DependencyProperty is using a CoerceValueCallback to ensure the values remain in range. However, what happens when you do this is FUBAR. When you call SetValue on the DependencyProperty this is roughly what happens:

>  1. Any BindingExpression sources are updated with the value.2. The CoerceValueCallback (if present) is called to coerce the value.3. The coerced value is used to set the actual DependencyValue property.

Bill Kempf

unread,
Mar 30, 2011, 1:39:49 PM3/30/11
to wpf-di...@googlegroups.com
That's a workaround, yes, but a very sad one. This isn't a fix that can be applied at the control level, but instead has to be applied manually every time you bind to any DP that can be coerced. It also means duplicating the coercion logic in multiple places. :(

Peter O'Hanlon

unread,
Mar 30, 2011, 1:59:01 PM3/30/11
to wpf-di...@googlegroups.com
While I agree that it's FUBAR, another possible workround is just to use an Attached Behavior on the TextBox. Then it becomes a simple matter of applying it in Blend and hooking it up as appropriate - what I would do is attach it to the updown control, and associate the textbox with it - then just handle it as appropriate.
--
Peter O'Hanlon

Bill Kempf

unread,
Mar 30, 2011, 2:07:24 PM3/30/11
to wpf-di...@googlegroups.com
Handle what, exactly? The behavior would have a similar problem, AFAICT.

Peter O'Hanlon

unread,
Mar 30, 2011, 2:29:21 PM3/30/11
to wpf-di...@googlegroups.com
It's effectively a control on the input, do the text entry would check the value against the bounds. I'm just out having a bite right now, but when I get in I will knock an example together.



From: Bill Kempf
Sent: 30 March 2011 19:07
To: wpf-di...@googlegroups.com
Subject: Re: [WPF Disciples] CoerceValueCallback madness

Peter O'Hanlon

unread,
Mar 30, 2011, 2:35:18 PM3/30/11
to wpf-di...@googlegroups.com
Nevermind. I just spotted a massive hole in that logic.


Josh Smith

unread,
Mar 30, 2011, 2:37:26 PM3/30/11
to wpf-di...@googlegroups.com
I agree it sucks, but I don't see any better option.

Bill Kempf

unread,
Mar 30, 2011, 2:42:37 PM3/30/11
to wpf-di...@googlegroups.com
The best solution I see currently is to not use CoerceValueCallback, but do manual coercion in the PropertyChangedCallback. The downside here is that the value gets set, and then it gets reset, but it seems to be the best possible solution so far. :(
 
I really can't believe this is "works as designed". WTF!

Peter O'Hanlon

unread,
Mar 30, 2011, 2:49:40 PM3/30/11
to wpf-di...@googlegroups.com
It looks like this "feature" has been triaged to death.
--
Peter O'Hanlon

Kent Boogaart

unread,
Mar 31, 2011, 4:30:54 AM3/31/11
to WPF Disciples
This is another one of those issues that has me shaking my head in
dismay. The fact that it exists in the first place is bad enough, but
then for Microsoft to attempt to pass it off as "by design" is salt in
the wound.

I have seen this time and again on Connect and my frustration is
boiling over at this point. Are Microsoft actually *interested* in
fixing the problems with WPF, or is it all about the next new, shiny
thing? I can't help but wonder what would be if the SL resources had
instead been tasked with improving WPF. I feel like we might have a
single decent platform instead of two half-assed ones (glaring bugs
like this make it half-assed, IMO).

To be clear, this is not just about this one issue. It's about the
many WTFs I come up against time and again when attempting to work
with WPF and SL.

Am I the only one feeling this way?


On Mar 30, 7:49 pm, "Peter O'Hanlon" <pete.ohan...@gmail.com> wrote:
> It looks like this "feature" has been triaged to death.
>
> On 30 March 2011 19:42, Bill Kempf <weke...@gmail.com> wrote:
>
>
>
>
>
> > The best solution I see currently is to not use CoerceValueCallback, but do
> > manual coercion in the PropertyChangedCallback. The downside here is that
> > the value gets set, and then it gets reset, but it seems to be the best
> > possible solution so far. :(
>
> > I really can't believe this is "works as designed". WTF!
>
> > On Wed, Mar 30, 2011 at 2:37 PM, Josh Smith <flappleja...@gmail.com>wrote:
>
> >> I agree it sucks, but I don't see any better option.
>
> >> Josh
>
> >> On Wednesday, March 30, 2011, Bill Kempf <weke...@gmail.com> wrote:
> >> > That's a workaround, yes, but a very sad one. This isn't a fix that can
> >> be applied at the control level, but instead has to be applied manually
> >> every time you bind to any DP that can be coerced. It also means duplicating
> >> the coercion logic in multiple places. :(
>
> >> > On Wed, Mar 30, 2011 at 12:52 PM, Josh Smith <flappleja...@gmail.com>
> >> wrote:
>
> >> > I would use a value converter on the binding to coerce the value.
>
> >> > Josh
>
> >>http://connect.microsoft.com/VisualStudio/feedback/details/489775/wpf...),
> >> where Microsoft responded that this was "by design" with a very lame example
> >> meant to illustrate why the design exists.
> >> >>  I'm facing a very short deadline in which I've got to try and find a
> >> work around for this issue, unfortunately. I don't suppose anyone has any
> >> bright ideas here?
> >> >> --
> >> >>  Quidquid latine dictum sit, altum sonatur.
> >> >> - Whatever is said in Latin sounds profound.
>
> >> >> War is peace. Freedom is slavery.  Bugs are features.
>
> >> > --
> >> >  Quidquid latine dictum sit, altum sonatur.
> >> > - Whatever is said in Latin sounds profound.
>
> >> > War is peace. Freedom is slavery.  Bugs are features.
>
> > --
> >  Quidquid latine dictum sit, altum sonatur.
> > - Whatever is said in Latin sounds profound.
>
> > War is peace. Freedom is slavery.  Bugs are features.
>
> --
> Peter O'Hanlon- Hide quoted text -
>
> - Show quoted text -

Peter O'Hanlon

unread,
Mar 31, 2011, 4:40:43 AM3/31/11
to WPF Disciples
Judging by some recent threads and blog postings, as well as the FixWPF
campaign, no.

I don't want to rehash old territory here, but this apathy and malaise
is causing a lot of vocal resentment. Add to this things like the
recent NoDo farce and MS looks amateurish.

Bill Kempf

unread,
Mar 31, 2011, 10:28:49 AM3/31/11
to wpf-di...@googlegroups.com
Surprisingly, I'm often in the minority here. I'm very forgiving of little issues in large and complex frameworks, especially when the framework is as powerful as WPF is. However, with issues like this one, I agree with you entirely, Kent. Not just because it bit me hard and cost me, but because issues like this really don't have ANY valid workarounds. I mean, it's bad enough that I simply can't buy the "works as designed" line (who really believes this is the way it *should* work?), but it causes serious issues that you can't work around without applying manual hacks with every use. So, yeah, Microsoft really does need to spend some time just fixing WPF even if it means not developing fancy new features and taking away some effort in Silverlight land.
 
I'll have a follow up on some specific solutions available for my NumericUpDown situation, which may or may not apply to other CoerceValueCallback scenarios.

Peter O'Hanlon

unread,
Mar 31, 2011, 10:37:41 AM3/31/11
to wpf-di...@googlegroups.com
I just feel that what we've got now is half finished and Microsoft got bored and moved onto the next shiny thing.



From: Bill Kempf
Sent: 31 March 2011 15:28
To: wpf-di...@googlegroups.com
Subject: Re: [WPF Disciples] Re: CoerceValueCallback madness

Reply all
Reply to author
Forward
0 new messages