Posted by: Zeeshan Amjad | May 12, 2010

Doing Data Binding Debugging using Markup Extension


We saw several example of data binding here. But the main problem with data binding is to debug its code. But sometimes it is difficult to trace what is the source of the binding, its path and other important information. Here we are going to discuss one method to display that information.

The quickest method to do this is by inheriting one class from the Binding class. But we already saw that “ProvideValue” method of binding class is sealed so we cant override it. Here we are going to use the Markup extension. We already saw few examples of markup extension here, here and here.

Our first step is to make one markup extension class and override the “ProvideValue” method. Here is our first attempts.

  1:     public class TraceBindingExtension : MarkupExtension
  2:     {
  3: 
  4:         public override object ProvideValue(IServiceProvider serviceProvider)
  5:         {
  6:             return null;
  7:         }
  8:     }  

This extension is doing nothing. Now we are going to use the interface “IServiceProvider” which is passed as a parameter to “ProvideValue” method to get the services. Here we are going to get “IProvideValueTarget” to get provide value target. “IProvideValueTarget” is a simple interface that contains only two properties. Here is a class diagram of this interface.

IProvideValueTarget

Now we can easily get the Binding object, because it is a set as a TargetObject property of IProvideValueTarget interface. Once we get the binding object, we can display all the related information of binding for debugging purpose. Here is a simple code to demonstrate this.

  1: public class TraceBindingExtension : MarkupExtension
  2: {
  3: 
  4:     public override object ProvideValue(IServiceProvider serviceProvider)
  5:     {
  6:         IProvideValueTarget target = serviceProvider.GetService(typeof(IProvideValueTarget)) as IProvideValueTarget;
  7:         
  8:         if (target != null)
  9:         {
 10:             Binding binding = target.TargetObject as Binding;
 11: 
 12:             if (binding != null)
 13:             {
 14:                 Debug.WriteLine("Path = " + binding.Path.Path);
 15:                 Debug.WriteLine("Mode = " + binding.Mode);
 16:                 Debug.WriteLine("FallbackValue = " + binding.FallbackValue);
 17:                 Debug.WriteLine("Source = " + binding.Source);
 18:                 Debug.WriteLine("ElementName = " + binding.ElementName);
 19:                 Debug.WriteLine("Converter = " + binding.Converter);
 20:             }
 21:         }
 22: 
 23:         return null;
 24:     }
 25: }     
 26: 

The usage of this markup extension is very simple. First we are going to make new XML namespace in the XAML. Here is a code to do this.

  1: xmlns:local="clr-namespace:WpfMarkupExtension" 

Now we are going to use this as a converter of data binding. Here is a code to use this markup extension.

  1: <TextBlock Text="{Binding Path=Ordinal, Converter={local:TraceBindingExtension}}"/>

Now let’s take a look at complete program. Here is complete C# coding of the program.

  1: using System;
  2: using System.Collections.Generic;
  3: using System.Linq;
  4: using System.Text;
  5: using System.Windows;
  6: using System.Windows.Controls;
  7: using System.Windows.Data;
  8: using System.Windows.Documents;
  9: using System.Windows.Input;
 10: using System.Windows.Media;
 11: using System.Windows.Media.Imaging;
 12: using System.Windows.Navigation;
 13: using System.Windows.Shapes;
 14: using System.Windows.Markup;
 15: using System.ComponentModel;
 16: using System.Diagnostics;
 17: 
 18: namespace WpfMarkupExtension
 19: {
 20:     /// <summary>
 21:     /// Interaction logic for Window1.xaml
 22:     /// </summary>
 23:     public partial class Window1 : Window
 24:     {
 25:         private List<Numbers> numbers = new List<Numbers>();
 26: 
 27:         public Window1()
 28:         {
 29:             InitializeComponent();
 30: 
 31:             numbers.Add(new Numbers("1", "First", "I"));
 32:             numbers.Add(new Numbers("2", "Second", "II"));
 33:             numbers.Add(new Numbers("3", "Third", "III"));
 34:             numbers.Add(new Numbers("4", "Fourth", "IV"));
 35:             numbers.Add(new Numbers("5", "Fifth", "V"));
 36:             numbers.Add(new Numbers("6", "Sixth", "VI"));
 37:             numbers.Add(new Numbers("7", "Seventh", "VII"));
 38:             numbers.Add(new Numbers("8", "Eighth", "VIII"));
 39:             numbers.Add(new Numbers("9", "Ninth", "IX"));
 40:             numbers.Add(new Numbers("10", "Tenth", "X"));
 41: 
 42:             DataContext = numbers;
 43:         }
 44:     }
 45: 
 46:     public class TraceBindingExtension : MarkupExtension
 47:     {
 48: 
 49:         public override object ProvideValue(IServiceProvider serviceProvider)
 50:         {
 51:             IProvideValueTarget target = serviceProvider.GetService(typeof(IProvideValueTarget)) as IProvideValueTarget;
 52:             
 53:             if (target != null)
 54:             {
 55:                 Binding binding = target.TargetObject as Binding;
 56: 
 57:                 if (binding != null)
 58:                 {
 59:                     Debug.WriteLine("Path = " + binding.Path.Path);
 60:                     Debug.WriteLine("Mode = " + binding.Mode);
 61:                     Debug.WriteLine("FallbackValue = " + binding.FallbackValue);
 62:                     Debug.WriteLine("Source = " + binding.Source);
 63:                     Debug.WriteLine("ElementName = " + binding.ElementName);
 64:                     Debug.WriteLine("Converter = " + binding.Converter);
 65:                 }
 66:             }
 67: 
 68:             return null;
 69:         }
 70:     }     
 71: 
 72:     public class Numbers
 73:     {
 74:         public Numbers(String number, String ordinal, String roman)
 75:         {
 76:             Number = number;
 77:             Ordinal = ordinal;
 78:             Roman = roman;
 79:         }
 80: 
 81:         public String Number
 82:         { set; get; }
 83: 
 84:         public String Ordinal
 85:         { set; get; }
 86: 
 87:         public String Roman
 88:         { set; get; }
 89:     }
 90: }
 91: 

And here is complete XAML code of the program.

  1: <Window x:Class="WpfMarkupExtension.Window1"
  2:     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  3:     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  4:     xmlns:local="clr-namespace:WpfMarkupExtension"      
  5:     Title="Window1" Height="300" Width="300">
  6:     <Grid>
  7:         <ListBox Name="list" Margin="5" ItemsSource="{Binding}">
  8:             <ListBox.ItemTemplate>
  9:                 <DataTemplate>
 10:                     <TextBlock Text="{Binding Path=Ordinal, Converter={local:TraceBindingExtension}}"/>
 11:                 </DataTemplate>
 12:             </ListBox.ItemTemplate>
 13:         </ListBox>
 14:     </Grid>
 15: </Window>
 16: 

 

If we run this program in debug mode, then we will be able to see binding related information in output window. The output of the program is not important here if we run it in release mode. Here is the output of the program.

DebugBindingOutput

Here is the debug output of the program.

Path = Ordinal

Mode = Default

FallbackValue = {DependencyProperty.UnsetValue}

Source =

ElementName =

Converter =

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Categories

%d bloggers like this: