Debugging Dependency Properties in WPF: Addendum
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.