« Broken: RichTextBoxes with embedded UIElements | Main | Tired of the Apple iPhone yet? »

Dependency Property Sets and duplicates ...

The question of the day:

"How do I get all of the dependency property sets, regardless of whether or not they might be equal to the previous value?"

Here's one way.

If you have a DependencyProperty, say it's called CPULoad in a class called MonitorControl (a graph of some sort):

public static readonly DependencyProperty CPULoadProperty =
DependencyProperty.Register("CPULoad", typeof(double),
typeof(MonitorControl),
new FrameworkPropertyMetadata(0.0,
FrameworkPropertyMetadataOptions.AffectsRender,
new PropertyChangedCallback(CPULoadChangedHandler)));

Your host application sets the CPULoad property routinely as normal operation (either via the CLR property CPULoad or a SetValue(MontiorControl.CPULoadProperty,{value}). But in this CPULoad property, you actually want to save values over time to graph a history, so you need to record each instance of the property as it is set. By design, DependencyProperties do not call the PropertyChangedCallback method unless the value has actually changed (makes sense, and prevents some unnecessary coding by the developer). So, in this example, the CPULoad DP callback would only get called if the CPULoad changed. That would mean the graph wouldn't update.

So, here's the cheating workaround I discovered:

public static readonly DependencyProperty CPULoadProperty =
DependencyProperty.Register("CPULoad", typeof(double),
typeof(MonitorControl),
new FrameworkPropertyMetadata(0.0,
FrameworkPropertyMetadataOptions.AffectsRender,
new PropertyChangedCallback(CPULoadChangedHandler),
new CoerceValueCallback(CPULoadCoerceHandler)
));

Add the CoerceValueCallback to the FrameworkPropertyMetadata constructor. Although designed to "coerce" a value, it can be used for other devious means as you'll see:

private static object CPULoadCoerceHandler(DependencyObject d,
object baseValue)
{
MonitorControl mc = d as MonitorControl;
if (mc != null && baseValue != null)
{
mc.CPULoadChanged((double)baseValue);
}
return baseValue;
}

In this case, the CPULoadCoerceHandler is called everytime the CPULoad DP property is set! So, within that method, the code casts to the MonitorControl class (the host class for the DP in this instance), and then calls the CPULoadChanged method (which is the same method that the CPULoadChangedHandler calls when the property actually changes (via the PropertyChangedCallback). The baseValue isn't changed at all -- it's just returned unchanged. A hack for doubles that works if you don't mind a slight loss in precision would be to tweak the baseValue ever so slightly as it comes through if the value was the same as the previous value.

It's sneaky, but effective. I'd bet someone Microsoft slaps their forehead in disgust after seeing this!

Help support my web site by searching and buying through Amazon.com (in assocation with Amazon.com).