Debugging Data Bindings in a WPF or Silverlight Application
The WPF and Silverlight platforms use late bound data binding resolution for bindings in XAML files. This feature allows a DataContext to be set at run-time and the objects within that DataContext to resolve their property bindings then. This late binding enables cool features like DataTemplates, composable applications and run-time loading of loose XAML.
A side effect of late bound binding resolution that can cause developers some minor frustration is that their controls do not display the expected data at run-time.
This article will explain troubleshooting techniques that can help you locate and correct the problem.
Data Binding Overview
Data binding is fundamental to WPF and Silverlight. You will struggle with your application designs, coding and troubleshooting until you understand data binding in these platforms.
The best data binding resource available is the MSDN Data Binding Overview topic. If you have not read or don't fully understand the material in this topic, please take the required amount of time to learn this material.
Ounce of Prevention is Worth a Pound of Cure
Visual Studio 2010 has great tooling to wire up data bindings and checked them at design-time. Please read this article: How to Enable Using the Binding Builder in WPF and Silverlight Applications.
Visual Studio 2010 has excellent design-time sample data support. If you use design-time sample data, you'll immediately see controls that don't have expected data values at design-time.
For a detailed examination of sample data in the WPF and Silverlight Designer for Visual Studio 2010, please read this article: Sample Data in the WPF and Silverlight Designer.
Troubleshooting List
- Verify that DataContext is set in either XAML or code
-
Run the application and view the output in the Debug Output Window
- For WPF applications you can increase or decrease the amount of information displayed in the Debug Output Window by changing the WPF Trace Settings, Data Binding value
- Name the control that has DataContext assigned, set a break point in the code, and view the named control's DataContext property in the debugger
- If binding to a CLR object, put a breakpoint in the source property getter to see that its actually being queried
- Add a converter to a binding, then put a breakpoint in the converter
Verify that DataContext is set in either XAML or Code
This tip is along the lines of, "if the TV won't turn on, check that it's plugged in."
This is important for many reasons, but one is easily overlooked; if a DataContext is null, the Debug Output Window will not display any error messages in Silverlight or in WPF.
In WPF you can use the below PresentationTraceSources on a binding and set the TraceLevel to High to view errors related to a null DataContext.
View the Debug Output Window
If you have the DataContext set, any data bindings within that DataContext that can't be resolved will be listed in the Debug Output Window at run-time.
Sample Debug Output Window Data Binding Error
Sample One
System.Windows.Data Error: 40 : BindingExpression path error: 'FirstName' property not found on 'object' ''Object' (HashCode=62178992)'. BindingExpression:Path=FirstName; DataItem='Object' (HashCode=62178992); target element is 'TextBox' (Name=''); target property is 'Text' (type 'String')
Sample Two
System.Windows.Data Error: 40 : BindingExpression path error: 'FirstName' property not found on 'object' ''Customer' (HashCode=13640894)'. BindingExpression:Path=FirstName; DataItem='Customer' (HashCode=13640894); target element is 'TextBox' (Name=''); target property is 'Tag' (type 'Object')
While the above messages look verbose and complex, you can glean several interesting points of information that will help you correct this data binding:
- The Binding Path is FirstName. Search your XAML file for FirstName and see if you expect the DataContext to expose a FirstName property whose scope will allow this binding to resolve this property.
- The Source object in Sample One is of Type Object. There is a good chance the Type Object does not have a FirstName property.
- The Source object in Sample Two is of Type Customer. Check your Customer Type; does it have a FirstName property?
- Notice in Sample Two, the target property is Tag. In all likelihood, the Text property was the desired target property and not Tag. Also the Type of Tag is Object; you would probably be expecting String when binding to the FirstName property.
Review
- Verify the property name is spelled correctly
- Verify the property name has the correct character casing. FirstName is not the same as firstName.
- Verify the property is a member of the DataContext Type
- Verify the target element is the correct Type
- Verify the target property name and Type are correct
Important |
Data binding property path names are Case Sensitive. |
WPF Trace Settings, Data Binding
Important |
The default value of the WPF Trace Settings, Data Binding is "Error." It is recommended that you change this setting to "Warning." Please read this short blog post for more information. This is required if you use the attached property PresentationTraceSources.TraceLevel. If the value is set to "Error" you won't see any of the PresentationTraceSources.TraceLevel warning messages. |
To change the WPF Trace Settings, Data Binding value to "Warning," navigate to Tools, Options, Debugging, Output Window, WPF Trace Settings, Data Binding and set the value to Warning as I've done in the below image.
Note |
This setting affects all bindings in WPF the application. For a more targeting approach, see the PresentationTraceSources.TraceLevel section below. |
Important |
If this setting is set to, "Off" you will not see any WPF Data Binding Errors in the Debug Output Window. |
PresentationTraceSources.TraceLevel
Introduced to WPF in .NET 3.5 SP1, the PresentationTraceSources.TraceLevel attached property allows developers to dial up the amount of information outputted in the Debugger Output Window for a binding.
The below XAML snippet shows how to apply the PresentationTraceSources.TraceLevel attached property to a binding.
<Window xmlns:diag="clr-namespace:System.Diagnostics;assembly=WindowsBase" xmlns:local="clr-namespace:DebugDataBindings" x:Class="DebugDataBindings.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="MainWindow" Height="350" Width="525"> <Grid x:Name="layoutRoot"> <Grid.Resources> <local:DebugConverter x:Key="debugConverter" /> </Grid.Resources> <TextBox Text="{Binding Path=Customer.FirstName, diag:PresentationTraceSources.TraceLevel=High}" Height="23" HorizontalAlignment="Left" Margin="90,18,0,0" VerticalAlignment="Top" Width="120"/> </Grid> </Window>
Use the Debugger Quick Watch to View the DataContext
If the above suggestions to do not solve your problem:
- Locate the control's parent panel like a Grid in your XAML
- Apply a x:Name to the control
- Set a break point in your code, and view the named panel control's DataContext property in the debugger
Open the QuickWatch dialog, change the Expression to the named control in the XAML and look at the control's DataContext property.
- In the below image, I have changed the Expression to, "this.layoutRoot.DataContext" in VB.NET you would change it to, , "Me.layoutRoot.DataContext"
This information will at least confirm the shape (Type) of the DataContext and the values inside the DataContext.
This tip provides value in two ways:
- If the DataContext had been set then subsequently changed by some other code, you'll be expecting the initial value but will see another value
-
If the property was nested within another class, you can easily see the shape of your DataContext and then ensure that your bindings are properly dotted in.
- Notice the path to the FirstName property is DataContext.Customer.FirstName.
-
This means that if you wanted to data bind to the Text property on a TextBox that was a child of the Grid named layoutRoot, the binding expression must read:
<TextBox Text="{Binding Path=Customer.FirstName}" ... />
Place a Breakpoint inside the Source Property Getter
If you are binding to a CLR object, put a breakpoint in the source property getter to see that it's actually being queried.
If it's not be queried, you have a mismatch in the property name, property is not properly dotted in, DataContext is null or does not contain this property.
Add a Converter to a binding, then put a Breakpoint in the Converter
Important |
The use of a converter to troubleshoot a data binding only works if the DataContext is not null, and the DataContext Type exposes a property with the same name in the binding expression. |
A ValueConverter allows you to view the data as its being moved between the target and source. In the below image the converter in the middle is named "ColorBrushConverter."
The below converter is a no-op converter named, "DebugConverter." This reusable converter will allow you to place a breakpoint in the Convert and ConvertBack methods and then view the value of the "value" parameter at debug time.
using System; using System.Windows.Data; namespace DebugDataBindings { public class DebugConverter : IValueConverter { public Object Convert(Object value, Type targetType, Object parameter, System.Globalization.CultureInfo culture) { //set a breakpoint here return value; } public Object ConvertBack(Object value, Type targetType, Object parameter, System.Globalization.CultureInfo culture) { //set a breakpoint here return value; } } }
The below XAML show the above converter being applied to the TextBox.Text property binding.
<Grid x:Name="layoutRoot"> <Grid.Resources> <local:DebugConverter x:Key="debugConverter" /> </Grid.Resources> <TextBox Text="{Binding Path=Customer.FirstName, Converter={StaticResource debugConverter}}" Height="23" HorizontalAlignment="Left" Margin="90,18,0,0" VerticalAlignment="Top" Width="120"/> </Grid>
Comments
Microsoft values your opinion about our products and documentation. In addition to your general feedback it is very helpful to understand:
- How the above features enable your workflow
- What is missing from the above features that would be helpful to you
Thank you for your feedback and have a great day,
Karl Shifflett Expression Team