Since DataBinding is one of the most important and useful features of WPF, here are some Tips & Tricks regarding it:
- DataBinding CheatSheat – This is a nice pdf summarizing most of DataBinding properties and options (via NBD Tech post)
- Debugging Tips-
- Look at the Visual Studio output window – It provides high level details about the binding and is sufficient to “easy” problems like naming mismatch: If we want to bind to this Person class:
class Person { public string FirstName { get; set; } public string LastName { get; set; } }
and have this XMAL:
<TextBlock Text="{Binding Path=Name, Mode=OneWay}"/>
you will see the following error in the output window:
System.Windows.Data Error: 39 : BindingExpression path error: Name' property not found on 'object' ''Person' (HashCode=1056119)'. BindingExpression:Path=Name; DataItem='Person' (HashCode=1056119); target element is 'TextBlock' (Name=''); target property is 'Text' (type 'String')
-
- Use TraceLevel
TraceLevel is an AttachedProperty introduced on .net 3.5, which adds trace information to the VS output window. In order to use it, you first need to add this xml namespace:
xmlns:diag="clr-namespace:System.Diagnostics;assembly=WindowsBase"
and then add the TraceLevel to the appropriate binding:
<TextBlock Text="{Binding Path=Name, Mode=OneWay, diag:PresentationTraceSources.TraceLevel=High}"/>
The output window will contain a detailed trace:
System.Windows.Data Warning: 52 : Created BindingExpression (hash=35885827) for Binding (hash=37710717)
System.Windows.Data Warning: 54 : Path: ‘Name’
System.Windows.Data Warning: 57 : BindingExpression (hash=35885827): Default update trigger resolved to PropertyChanged
System.Windows.Data Warning: 58 : BindingExpression (hash=35885827): Attach to System.Windows.Controls.TextBlock.Text (hash=13575069)
System.Windows.Data Warning: 63 : BindingExpression (hash=35885827): Resolving source
System.Windows.Data Warning: 66 : BindingExpression (hash=35885827): Found data context element: TextBlock (hash=13575069) (OK)
System.Windows.Data Warning: 67 : BindingExpression (hash=35885827): DataContext is null
System.Windows.Data Warning: 61 : BindingExpression (hash=35885827): Resolve source deferred
‘BindingSample.vshost.exe’ (Managed): Loaded ‘C:\WINDOWS\assembly\GAC_MSIL\PresentationFramework.Luna\3.0.0.0__31bf3856ad364e35\PresentationFramework.Luna.dll’, Skipped loading symbols. Module is optimized and the debugger option ‘Just My Code’ is enabled.
System.Windows.Data Warning: 63 : BindingExpression (hash=35885827): Resolving source
System.Windows.Data Warning: 66 : BindingExpression (hash=35885827): Found data context element: TextBlock (hash=13575069) (OK)
System.Windows.Data Warning: 74 : BindingExpression (hash=35885827): Activate with root item Person (hash=21577349)
System.Windows.Data Warning: 104 : BindingExpression (hash=35885827): At level 0 – for Person.Name found accessor <null>
System.Windows.Data Error: 39 : BindingExpression path error: ‘Name’ property not found on ‘object’ ”Person’ (HashCode=21577349)’. BindingExpression:Path=Name; DataItem=’Person’ (HashCode=21577349); target element is ‘TextBlock’ (Name=”); target property is ‘Text’ (type ‘String’)
System.Windows.Data Warning: 76 : BindingExpression (hash=35885827): TransferValue – got raw value {DependencyProperty.UnsetValue}
System.Windows.Data Warning: 84 : BindingExpression (hash=35885827): TransferValue – using fallback/default value ”
System.Windows.Data Warning: 85 : BindingExpression (hash=35885827): TransferValue – using final value ”
- Use an empty converter – You can set a converter on your binding, and set a breakpoint in the Convert\ConvertBack function. you can find a nice implementation of this in this post
- Snoop it – Using Snoop is always a good option for getting info about your app.
- The “Binding Errors” column can provide binding related info.
- The DataContext DP can provide info about the binding source.
StringFormat is a .NET 3.5 SP1 property which may be used for formatting strings in binding. For example, instead of using this:
<WrapPanel> <TextBlock Text="{Binding Path=FirstName, Mode=OneWay}"/> <TextBlock Text=" "/> <TextBlock Text="{Binding Path=LastName, Mode=OneWay}"/> </WrapPanel>
You may use this:
<WrapPanel> <TextBlock> <TextBlock.Text> <MultiBinding StringFormat="{}{0} {1}"> <Binding Path="FirstName" Mode="OneWay"/> <Binding Path="LastName" Mode="OneWay"/> </MultiBinding> </TextBlock.Text> </TextBlock> </WrapPanel>
The benefit here is double, there is only one binding instead of two, and only on TextBlock element instead of three. This may help performance especially when used as a DataTemplate of an ItemsControl with many items.
You may of course use the StringFormat for any other formatting you need (dates, currencies, etc.)
- Virtualizing –
When binding to a large collection, consider using the following attached properties:
- Explicitly state the Binding Mode – The default binding mode is set by binding target property type, which might not always be what you imagine… Besides, it contributes to your XAML\code readability. Of course, preferring the OneTime mode (If appropriate to your scenario) is best for performance.
- Try using less converters if performance is critical – Instead of using a converter which requires Boxing \ Unboxing, you can create a property in you ViewModel, do the converter in the getter, and bind to it.
- Binding.DoNothing – May be useful as return value in a converter when you have a scenario where you don’t want to “interfere” in the binding process (and use the FallbackValue for example).
- Binding in a non-visual tree element – Sometimes, a binding is needed in an element which does not inherit a context. most of the times, you will see the following error in this case:
System.Windows.Data Error: 2 : Cannot find governing FrameworkElement or FrameworkContentElement for target element…
There are several “tricks” to overcome this problem: