In my last couple posts, I've highlighted a way to inject debugging into dependency properties updated via data binding. It seems to work fine, but it's not clear how to apply it in certain scenarios. In our examples, we were attempting to debug a dependency property we defined on our own control. What if we want to debug an inherited property? It's not immediately obvious how to set property metadata in this case, but a little digging turns up some answers. Specifically, we can override default metadata:
1: static MyUserControl()
2: { 3: UserControl.WidthProperty.OverrideMetadata(typeof(MyUserControl),
4: new FrameworkPropertyMetadata(PrintfDebugger()));
5: }
And it works:
Here we use our control's static constructor to hook into the property changed callback. Notice that we're using FrameworkPropertyMetadata. I originally tried using the normal PropertyMetadata, but this resulted in a runtime exception. Apparently, you can only override metadata with the same type (or a derived type). Since WidthProperty uses FrameworkPropertyMetadata, so must we. Actually, I originally attempted to override metadata on ActualWidthProperty, but it turns out that this is impossible! ActualWidthProperty uses ReadOnlyFrameworkPropertyMetadata, which is an internal class. So we're out of luck if we want to get debug info on read-only properties.
Actually, there is something we can do. We can add a normal event handler to a dependency property descriptor like so:
1: public MyUserControl()
2: { 3: InitializeComponent();
4: DependencyPropertyDescriptor.FromProperty(UserControl.ActualWidthProperty,
5: typeof(MyUserControl)).AddValueChanged(this, (sender, e) =>
6: { 7:
8: });
9: }
Here we add an event handler that will fire whenever the value changes, allowing us to debug via normal means. This doesn't really fit in with our other solution, and we don't get nearly as much information as with the property changed callback, but I think it's the best we can do. Notice that we're using the regular constructor here and not the static one.
There's still one big scenario I've more or less ignored up to this point. Suppose you want to debug the properties of a child control that's not inherited at all? For example, suppose we host an ellipse in our user control like this:
1: <Grid>
2: <Ellipse Fill="Red" Height="50" Width="{Binding ActualWidth, ElementName=root}"/> 3: </Grid>
How can we debug that property? The Ellipse isn't our class, so it's not obvious how we can hook into its property's metadata. As it turns out, we can override the metadata on other classes:
1: static MyUserControl()
2: { 3: Ellipse.HeightProperty.OverrideMetadata(typeof(Ellipse),
4: new FrameworkPropertyMetadata(PrintfDebugger()));
5: }
This yields the desired result, hooking our debugger into the property updates:
Something doesn't feel quite right, though, does it? This ellipse already had some metadata, and we just stomped all over it. Our debugging is going to be pretty worthless if it produces any side effects. Unfortunately, ensuring the original metadata stays intact turns out to be much harder than you'd think.
1: static MyUserControl()
2: { 3: var metadata =
4: (FrameworkPropertyMetadata)Ellipse.HeightProperty.GetMetadata(typeof(Ellipse));
5: Ellipse.HeightProperty
6: .OverrideMetadata(typeof(Ellipse), GetDebugMetadata(metadata));
7: }
8:
9: public static FrameworkPropertyMetadata GetDebugMetadata(FrameworkPropertyMetadata metadata)
10: { 11: var flags = FrameworkPropertyMetadataOptions.None;
12: if (metadata.AffectsMeasure)
13: flags |= FrameworkPropertyMetadataOptions.AffectsMeasure;
14: if (metadata.AffectsArrange)
15: flags |= FrameworkPropertyMetadataOptions.AffectsArrange;
16: if (metadata.AffectsParentMeasure)
17: flags |= FrameworkPropertyMetadataOptions.AffectsParentMeasure;
18: if (metadata.AffectsParentArrange)
19: flags |= FrameworkPropertyMetadataOptions.AffectsParentArrange;
20: if (metadata.AffectsRender)
21: flags |= FrameworkPropertyMetadataOptions.AffectsRender;
22: if (metadata.Inherits)
23: flags |= FrameworkPropertyMetadataOptions.Inherits;
24: if (metadata.OverridesInheritanceBehavior)
25: flags |= FrameworkPropertyMetadataOptions.OverridesInheritanceBehavior;
26: if (metadata.IsNotDataBindable)
27: flags |= FrameworkPropertyMetadataOptions.NotDataBindable;
28: if (metadata.BindsTwoWayByDefault)
29: flags |= FrameworkPropertyMetadataOptions.BindsTwoWayByDefault;
30: if (metadata.Journal)
31: flags |= FrameworkPropertyMetadataOptions.Journal;
32: if (metadata.SubPropertiesDoNotAffectRender)
33: flags |= FrameworkPropertyMetadataOptions.SubPropertiesDoNotAffectRender;
34:
35: return new FrameworkPropertyMetadata(metadata.DefaultValue, flags,
36: PrintfDebugger(metadata.PropertyChangedCallback), metadata.CoerceValueCallback,
37: metadata.IsAnimationProhibited, metadata.DefaultUpdateSourceTrigger);
38: }
Pretty ugly, huh? Sorry for the giant wall of code. Here we define another static method to build up a new piece of metadata that's identical save for the injected debugging. The biggest pain is that the flags aren't exposed publicly, so we have to reverse engineer them based on the exposed Boolean properties. We use the bitwise OR operator to build up the flags. (Incidentally, I didn't even realize "|=" was a valid operator in C#; I was pleasantly surprised when I tried it, and it worked.) The rest is pretty straightforward. We pass in all the info from the original metadata and return, preserving the original functionality while injecting our own debugging method.
This is going to be a pretty brief post. I just wanted to mention a small addition to the data binding debugging solution I posted about last time. When we left off, we had a pretty decent solution to debugging via a property changed callback. And here it is:
1: public static PropertyChangedCallback PrintfDebugger
2: (PropertyChangedCallback propertyChangedCallback)
3: { 4: return (d, e) =>
5: { 6: propertyChangedCallback(d, e);
7: Console.WriteLine("{0}.{1}: {2}", 8: d.DependencyObjectType.Name,
9: e.Property.Name,
10: e.NewValue);
11: };
12: }
This works fine, but it's slightly limited. One common scenario where this might not be so useful is if you have several of the same type of control on the same page. This would make it pretty difficult to tell which control is actually receiving the update. What can we do? Well, we can mitigate this by using the name of the element, if it exists.
1: public static PropertyChangedCallback PrintfDebugger
2: (PropertyChangedCallback propertyChangedCallback)
3: { 4: return (d, e) =>
5: { 6: propertyChangedCallback(d, e);
7: var elem = d as FrameworkElement;
8: string name = elem != null && !string.IsNullOrEmpty(elem.Name) ?
9: elem.Name :
10: d.DependencyObjectType.Name;
11: Console.WriteLine("{0}.{1}: {2}", 12: name,
13: e.Property.Name,
14: e.NewValue);
15: };
16: }
Here we check to see if the dependency object is a FrameworkElement. If it is, and it has a name, we use that. Otherwise, we default to the class name. Note that there are other classes that implement a Name property, but, for the sake of simplicity, I've restricted this to what I believe is the most common scenario. Now, let's see it in action. First, we'll confirm that it still works in our previous case by leaving the control unnamed, like so:
1: <Grid>
2: <local:MyUserControl MyProperty="{Binding ActualWidth, ElementName=root}"/> 3: </Grid>
And running it yields the desired result:
Now, let's add a second named control with the same binding.
1: <Grid>
2: <local:MyUserControl MyProperty="{Binding ActualWidth, ElementName=root}"/> 3: <local:MyUserControl x:Name="newControl" MyProperty="{Binding ActualWidth, ElementName=root}"/> 4: </Grid>
And the moment of truth:
Nice.
WPF is a great technology. It's changed the way we write rich desktop apps for Windows. But after using it for an appreciable length of time (eight or nine months), I've come to two conclusions:
1. Data binding sure is swell.
2. Data binding sure is a pain to debug.
I think this is the case with most powerful frameworks. You invoke a few lines of magic, and the tool takes care of all the low level wiring code for you. The problem comes when you treat this process like a black box; when you run into the edge cases where the abstraction starts to break down, it puts you in a tough spot when you try to track down the problem. So it is for debugging data binding with dependency properties in WPF. When a complex chain of bound data isn't working correctly, it can often be difficult to tell where the system is breaking down. To understand why this is, first we need to know a little bit about how dependency properties work in WPF. This is a pretty standard definition of a dependency property:
1: public double MyProperty
2: { 3: get { return (double)GetValue(MyPropertyProperty); } 4: set { SetValue(MyPropertyProperty, value); } 5: }
6: public static readonly DependencyProperty MyPropertyProperty =
7: DependencyProperty.Register("MyProperty", typeof(double), typeof(MyUserControl));
There are a few things to note here. First, the regular .NET property (MyProperty) is simply a wrapper around the dependency property. The actual data will be associated with the dependency property defined just below. Also, take a look at the method calls inside the plain .NET property's get and set methods. These are used to store and retrieve information with our dependency property. More importantly, they will be called directly when our dependency property is updated via data binding. This brings us to the root of the problem: we can't debug dependency properties with our normal techniques, because they are updated with methods we have no insight into. There's nowhere to set a break point.
But there must be something we can do, right? There is. Let's take a closer look at the call to DependencyProperty.Register. This is where we're creating a static definition of the property to be used by instances of our class. You can see that we're currently passing three parameters: the name of the property, the type of the property, and the type of the owning property (i.e. our class). But there's also an optional fourth parameter: property metadata. Property metadata allows you to define some additional behaviors for your dependency property. Among these is the concept of a property changed callback; that is, a method that will run each time your dependency property is updated. This is commonly used for validation or to provide explicit updates to other properties in edge cases when data binding won't do, but we're going to use it to log changes to the console. Doing so is as simple as it sounds:
1: public static readonly DependencyProperty MyPropertyProperty =
2: DependencyProperty.Register("MyProperty", typeof(double), typeof(MyUserControl), 3: new PropertyMetadata((d, e) =>
4: { 5: Console.WriteLine("MyUserControl.MyProperty: {0}", e.NewValue); 6: }));
You can see here that we're passing in the additional property metadata, which in turn takes our property changed callback as a parameter. Here we define the callback inline via a lambda method. Our method body is extremely simple: we log a formatted message to the console (your output window, if you're debugging in Visual Studio). This should feel familiar to anyone who's done an appreciable amount of C/C++ development. Welcome back, printf debugging! For demo purposes, I have MyProperty bound to the actual width of the main window, like so:
1: <Grid>
2: <local:MyUserControl MyProperty="{Binding ActualWidth, ElementName=root}"/> 3: </Grid>
No magic here. When we run and resize the window . . .
We see the output as expected.
Is this good enough? Maybe for infrequent use, but it's kind of a pain. I know I wouldn't want to be littering my code with snippets like this, nor would I be very excited about manually editing that format string in every instance. I'm likely as not to forget to do it somewhere and end up with bad debugging info, and that's worse than no info at all. How can we make something more reusable? How about this:
1: public static readonly DependencyProperty MyPropertyProperty =
2: DependencyProperty.Register("MyProperty", typeof(double), typeof(MyUserControl), 3: new PropertyMetadata(PrintfDebugger));
4:
5: public static void PrintfDebugger(DependencyObject d, DependencyPropertyChangedEventArgs e)
6: { 7: Console.WriteLine("{0}.{1}: {2}", 8: d.DependencyObjectType.Name,
9: e.Property.Name,
10: e.NewValue);
11: }
Here we extract out our inline declaration into a reusable method. Note also that all class and property name information comes directly from the parameters themselves. If you try this out, you'll find that everything still works as expected. Astute readers will notice a minor problem with this approach. Our original solution was versatile in that it could fit inside any previously declared property changed callbacks. Here, with our debugging method in place, it seems like we can't run any other code when the dependency property changes.
There is an elegant solution, but it requires us to borrow an idea from functional programming: composition. Composition is the idea of using functions that take functions as parameters and return functions upon invocation; this is a popular technique in functional programming because it allows you to chain methods together in such a way as to easily inject new functionality. It's a perfect fit for our case. However, it's a little bit confusing, if you're not familiar with the concept, and my poor explanation probably doesn't help much. So let's jump into some code:
1: public static readonly DependencyProperty MyPropertyProperty =
2: DependencyProperty.Register("MyProperty", typeof(double), typeof(MyUserControl), 3: new PropertyMetadata(PrintfDebugger((d, e) =>
4: { 5: if ((double)e.NewValue > 700.0)
6: MessageBox.Show("wide load!"); 7: })));
8:
9: public static PropertyChangedCallback PrintfDebugger
10: (PropertyChangedCallback propertyChangedCallback)
11: { 12: return (d, e) =>
13: { 14: propertyChangedCallback(d, e);
15: Console.WriteLine("{0}.{1}: {2}", 16: d.DependencyObjectType.Name,
17: e.Property.Name,
18: e.NewValue);
19: };
20: }
This might be a lot to take in all at once, so let's break it down. Look at the PrintfDebugger method's signature. It takes a PropertyChangedCallback and returns one. It may seem a little odd, but it seems intuitively correct; if we're going to be chaining methods like this, both ends need to match up (hint: think of it like an extension cord). Moving on to the body, you can see that we're creating a PropertyChangedCallback inline and immediately returning it. Inside the body of our return function, you can see that we're invoking the actual callback function (passed to us as a parameter) and then logging out our debug info.
At this point, you may be feeling slightly uneasy about something you can't quite put your finger on. It's probably the invocation of propertyChangedCallback. We're not passing it in as a parameter to our inline function; instead, we're capturing a reference to it through a technique known as closure. Because the callback is in scope when our inline function is declared, it has access to it. And because it chooses to make use of it, the callback will remain in existence as long as our inline function exists. This is another powerful technique in functional programming that really makes the rest of it possible. We'd have a pretty tough time building up functions dynamically like this without closures.
Moving on to our dependency property, you can see that we're passing our own (trivial) callback to our PrintfDebugger method. Running the program, we see that everything works as we expect it to:
For completeness, let's add an overload to PrintfDebugger with no parameters:
1: public static readonly DependencyProperty MyPropertyProperty =
2: DependencyProperty.Register("MyProperty", typeof(double), typeof(MyUserControl), 3: new PropertyMetadata(PrintfDebugger()));
4:
5: public static PropertyChangedCallback PrintfDebugger()
6: { 7: return PrintfDebugger((d, e) => { }); 8: }
This simply calls the other method with an empty delegate as the parameter. It also allows me to highlight a crucial point: we are not passing PrintfDebugger as the parameter to PropertyMetadata. We're passing the invocation of PrintfDebugger. To put it another way, PropertyMetadata takes a PropertyChangedCallback as a parameter, and PrintfDebugger is not one. Rather, PrintfDebugger is a function that builds PropertyChangedCallbacks. Here's some code to clarify:
1: // this works: PrintfDebugger is invoked and returns a method
2: public static readonly DependencyProperty MyPropertyProperty =
3: DependencyProperty.Register("MyProperty", typeof(double), typeof(MyUserControl), 4: new PropertyMetadata(PrintfDebugger()));
5:
6: // this doesn't: we attempt to pass PrintfDebugger as a delegate
7: public static readonly DependencyProperty MyPropertyProperty =
8: DependencyProperty.Register("MyProperty", typeof(double), typeof(MyUserControl), 9: new PropertyMetadata(PrintfDebugger));
Anyway, I hope this helps some of you to ease the occasional pain WPF development can be.