Build your own databinding inspector in Silverlight Spy

Silverlight Spy is a runtime inspector tool providing a lot of information about your Silverlight application. However, sometimes that information is just not sufficient. Let me explain this with the following use case; you want to have an overview of all databindings that are available in your application and you want to know whether these bindings are valid or not. Silverlight Spy does provide databinding information in its data bindings tab of the property grid, but it doesn't provide a convenient list of all databindings.

 

DLR Shell

Dynamic Language Runtime (DLR) Shell to the rescue! If you encounter a limitation such as the one outlined above, you have the option to build such a feature yourself using the DLR Shell that is available in Silverlight Spy.

Use the DLR shell to execute DLR code such as Python and Ruby in the Silverlight application domain. You do not need to add the DLR assemblies to your application, Silverlight Spy takes care of the proper loading and initialization of the DLR runtime.

In this post a demonstration of the powerful DLR shell. I will create a Python script of only 40 lines that contains a complete databinding inspector. The code iterates over all dependency properties of all elements in the UI visual tree. For each dependency property where a binding is established, it lists the binding details and it will tell you whether the binding is valid or not.

 

FirstFloor.SilverlightSpy.Interop

First of all I need to iterate over all dependency properties of all UI elements in the visual tree. In order to so, I will use helper classes available in the FirstFloor.SilverlightSpy.Interop assembly. This assembly is always available when running a Silverlight application in Silverlight Spy. The static VisualTreeHelperEx class contains various methods for iterating the visual tree. We will use the Descendants method and feed it the root visual to get the complete list of all UI elements.

To retrieve the list of all dependency properties available on each element, I will use the static DependencyObjectExtensions class that contains methods for retrieving dependency property info. The resulting info is encapsulated in a class DependencyPropertyInfo, providing some useful data of a dependency property. The following Python snippet calculates the total amount of dependency properties found in the visual tree;

from System.Windows import *
from System.Windows.Data import *
from FirstFloor.SilverlightSpy.Interop import *

propertyCount = 0

for element in VisualTreeHelperEx.Descendants(Application.Current.RootVisual):
    for property in DependencyObjectExtensions.DependencyProperties(element):
        propertyCount += 1

print 'Found ' + str(propertyCount) + ' dependency properties.'

 

Binding details

With the main iteration logic in place, I now need to inspect each dependency property and determine whether it contains a data binding. This can be accomplished by using the DependencyObject.ReadLocalValue and test if the output is of type BindingExpression. If this is the case, I want to output some binding details including the markup expression of the binding. The Silverlight Spy Formatter class is another useful class which helps me to format the markup expression of a binding. The following Python snippet prints the details of a data binding.

value = element.ReadLocalValue(property.Property)
if (isinstance(value, BindingExpression)):
    binding = value.ParentBinding

    print 'Binding source: ' + value.DataItem.GetType().FullName
    print 'Binding target: ' + element.GetType().Name + '.' + property.PropertyName
    print 'Binding       : ' + Formatter.Format(binding)

 

Validating the binding

Finally I need to validate whether a binding is valid. A binding is considered invalid when the binding path references an incorrect source property. The inspector I am building evaluates the binding path against the provided binding source. The binding source is available as DataItem property on the BindingExpression I retrieved earlier. If the binding source is not null I will use the Python eval function in combination with an exception handler to verify whether the path is valid. The following Python function demonstrates the validator:

def IsValidBinding(binding, context):
    try:
        path = binding.Path.Path
        if (len(path) > 0):
            eval("context." + path)
            return True
        else:
            return context != None
    except:
        return False

And that's it! The databinding inspector is now complete. Download the entire Python code and run it in the DLR shell. See if you can spot any binding errors in your application.

 

Final notes

  • The demonstrated databinding inspector does not take non-UI element dependency properties into account, that is the dependency properties of Foreground, Background, Rendertransform, etc. That is okay for Silverlight 3 applications, but as of Silverlight 4 Beta you can establish bindings on dependency properties of any dependency object (not just UI elements).
  • Indentation is significant in the Python language, make sure you properly indent your code blocks.
  • Learn more about programming with the DLR shell in Silverlight Spy:

 

Published: December 14, 2009

1 Comment

  1. Miguel Madero said: says:

    Awesome!!!

 

Leave a comment

Comments are closed for this post