How to detect broken WPF Data binding?

WpfData Binding

Wpf Problem Overview


While trying to answer a question in the vicinity 'Unit Testing WPF Bindings' I had the following niggling question..
What's the best way to find if you have WPF Data Binding wiring setup incorrectly (or you just broke something that was wired up correctly) ?

Although the unit-testing approach seems to be like Joel's 'ripping off your arm to remove a splinter'.. I am looking around for easier less Overhead ways to detect this.

Everyone seems to have committed themselves to data binding in a big way with WPF.. and it does have its merits.

Wpf Solutions


Solution 1 - Wpf

In .NET 3.5 it was introduced a new way to specifically output tracing information about specific data bindings.

This is done through the new System.Diagnostics.PresentationTraceSources.TraceLevel attached property that you can apply to any binding or data provider. Here is an example:

<Window x:Class="WpfApplication1.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:diag="clr-namespace:System.Diagnostics;assembly=WindowsBase"
    Title="Debug Binding Sample"
    Height="300"
    Width="300">
    <StackPanel>
        <TextBox Name="txtInput" />
        <Label>
            <Label.Content>
                <Binding ElementName="txtInput"
                         Path="Text"
                         diag:PresentationTraceSources.TraceLevel="High" />
            </Label.Content>
        </Label>
    </StackPanel>
</Window>

This will put trace information for just that particular binding in Visual Studio's Output Window, without any tracing configuration required.

Solution 2 - Wpf

Best I could find...

How can I debug WPF Bindings? by Beatriz Stollnitz

Since everyone can't always keep one eye on the Output Window looking for Binding errors, I loved Option#2. Which is add this to your App.Config

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <system.diagnostics>
    <sources>
      <source name="System.Windows.Data" switchName="SourceSwitch" >
        <listeners>
          <add name="textListener" />
        </listeners>
      </source>

    </sources>
      <switches>
        <add name="SourceSwitch" value="All" />
      </switches>

      <sharedListeners>
        <add name="textListener"
        type="System.Diagnostics.TextWriterTraceListener"
        initializeData="GraveOfBindErrors.txt" />
      </sharedListeners>

      <trace autoflush="true" indentsize="4"></trace>
  
  </system.diagnostics>
</configuration>

Pair that up with a good regex scan script to extract out relevant info, that you can run occasionally on the GraveOfBindErrors.txt in your output folder

System.Windows.Data Error: 35 : BindingExpression path error: 'MyProperty' property not found on 'object' ''MyWindow' (Name='')'. BindingExpression:Path=MyProperty; DataItem='MyWindow' (Name=''); target element is 'TextBox' (Name='txtValue2'); target property is 'Text' (type 'String')

Solution 3 - Wpf

I use the solution presented here to turn binding errors into native Exceptions: http://www.jasonbock.net/jb/Default.aspx?blog=entry.0f221e047de740ee90722b248933a28d

However, a normal scenario in WPF bindings is to throw exceptions in case the user input cannot be converted to the target type (for instance, a TextBox bound to a integer field; the input of a non-numeric string results in a FormatException, the input of number that is too large results in an OverflowException). A similar case is when the Setter of the source property throws an exception.

The WPF way of handling this is via ValidatesOnExceptions=true and ValidationExceptionRule to signal the user the supplied input is not correct (using the exception message).

However, these exception are also send to the output window and thus 'caught' by the BindingListener, resulting in an error...clearly not the behaviour you'd want.

Therefore, I expanded the BindingListener class to NOT throw an Exception in these cases:

private static readonly IList<string> m_MessagesToIgnore =
        new List<String>()
        {
            //Windows.Data.Error 7
            //Binding transfer from target to source failed because of an exception
            //Normal WPF Scenario, requires ValidatesOnExceptions / ExceptionValidationRule
            //To cope with these kind of errors
            "ConvertBack cannot convert value",

            //Windows.Data.Error 8
            //Binding transfer from target to source failed because of an exception
            //Normal WPF Scenario, requires ValidatesOnExceptions / ExceptionValidationRule
            //To cope with these kind of errors
            "Cannot save value from target back to source"  
        };

Modified lines in public override void WriteLine(string message):

        ....
        if (this.InformationPropertyCount == 0)
        {
            //Only treat message as an exception if it is not to be ignored
            if (!m_MessagesToIgnore.Any(
                x => this.Message.StartsWith(x, StringComparison.InvariantCultureIgnoreCase)))
            {
                PresentationTraceSources.DataBindingSource.Listeners.Remove(this);

                throw new BindingException(this.Message,
                    new BindingExceptionInformation(this.Callstack,
                        System.DateTime.Parse(this.DateTime),
                        this.LogicalOperationStack, int.Parse(this.ProcessId),
                        int.Parse(this.ThreadId), long.Parse(this.Timestamp)));
            }
            else
            {
                //Ignore message, reset values
                this.IsFirstWrite = true;
                this.DetermineInformationPropertyCount();
            }
        }
    }

Solution 4 - Wpf

You can use the trigger debugging feature of WPF Inspector. Just download the tool from codeplex and attach it to your running app. It also shows binding errors on the bottom of the window. Very useful tool!

enter image description here

Solution 5 - Wpf

Here's a useful technique for debugging/tracing triggers effectively. It allows you to log all trigger actions along with the element being acted upon:

http://www.wpfmentor.com/2009/01/how-to-debug-triggers-using-trigger.html">http://www.wpfmentor.com/2009/01/how-to-debug-triggers-using-trigger.html</a>

Solution 6 - Wpf

This was very helpful to us but I wanted to add to those who find this useful that there is a utility that Microsoft provides with the sdk to read this file.

Found here: http://msdn.microsoft.com/en-us/library/ms732023.aspx

> To open a trace file > > 1.Start Service Trace Viewer by using a command window to navigate to your > WCF installation location (C:\Program > Files\Microsoft > SDKs\Windows\v6.0\Bin), and then type > SvcTraceViewer.exe. (although we found ours in \v7.0\Bin) > > Note: The Service Trace Viewer tool > can associate with two file types: > .svclog and .stvproj. You can use two > parameters in command line to register > and unregister the file extensions. > > /register: register the association of > file extensions ".svclog" and > ".stvproj" with SvcTraceViewer.exe > > /unregister: unregister the > association of file extensions > ".svclog" and ".stvproj" with > SvcTraceViewer.exe >
> > > 1.When Service Trace Viewer starts, click File and then point to Open. > Navigate to the location where your > trace files are stored. > > > 2.Double-click the trace file that you want to open. > > > Note: Press SHIFT while clicking > multiple trace files to select and > open them simultaneously. Service > Trace Viewer merges the content of all > files and presents one view. For > example, you can open trace files of > both client and service. This is > useful when you have enabled message > logging and activity propagation in > configuration. In this way, you can > examine message exchange between > client and service. You can also drag > multiple files into the viewer, or use > the Project tab. See the Managing > Project section for more details. >
> > > 3.To add additional trace files to the collection that is open, click File > and then point to Add. In the window > that opens, navigate to the location > of the trace files and double-click > the file you want to add.

Also, as for the filtering of the log file, we found these this link extremely helpful:

http://msdn.microsoft.com/en-us/library/ms751526.aspx

Solution 7 - Wpf

For anyone like me looking for a pure programmatic way of enabling all WPF Tracing at a given Trace Level, here is a piece of code that does it. For reference, it's based on this article: Trace sources in WPF.

It doesn't requires a change in the app.config file, and it does not require to change the registry either.

This is how I use it, in some startup place (App, etc.):

....
#if DEBUG
    WpfUtilities.SetTracing();
#endif
....

And here is the utility code (by default it sends all Warning to the Default Trace Listener):

public static void SetTracing()
{
    SetTracing(SourceLevels.Warning, null);
}

public static void SetTracing(SourceLevels levels, TraceListener listener)
{
    if (listener == null)
    {
        listener = new DefaultTraceListener();
    }

    // enable WPF tracing
    PresentationTraceSources.Refresh();

    // enable all WPF Trace sources (change this if you only want DataBindingSource)
    foreach (PropertyInfo pi in typeof(PresentationTraceSources).GetProperties(BindingFlags.Static | BindingFlags.Public))
    {
        if (typeof(TraceSource).IsAssignableFrom(pi.PropertyType))
        {
            TraceSource ts = (TraceSource)pi.GetValue(null, null);
            ts.Listeners.Add(listener);
            ts.Switch.Level = levels;
        }
    }
}

Solution 8 - Wpf

My suggestion at 2021:

The Best way is to use Benoit Blanchon small library from Nuget

His original post at here: https://stackoverflow.com/a/19610384/6296708

His GitHub link and more info about how to use it + Nuget command: https://github.com/bblanchon/WpfBindingErrors

Its features (until now!):

  • throw exception on binding errors (+ line number)
  • If source Variable throw any exceptions, this library will catch it and show it.
  • Unit Test supports too!

Happy Coding!

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionGishuView Question on Stackoverflow
Solution 1 - WpfEnrico CampidoglioView Answer on Stackoverflow
Solution 2 - WpfGishuView Answer on Stackoverflow
Solution 3 - WpfJeroen de BekkerView Answer on Stackoverflow
Solution 4 - WpfChristian MoserView Answer on Stackoverflow
Solution 5 - WpfDan LampingView Answer on Stackoverflow
Solution 6 - WpfErocMView Answer on Stackoverflow
Solution 7 - WpfSimon MourierView Answer on Stackoverflow
Solution 8 - WpfMRKView Answer on Stackoverflow