How to locate the source of a binding error?

2019-01-17 01:20发布

问题:

How can I figure out what line of xaml contains the troublesome binding When my debug output is full of lines like the following:

System.Windows.Data Error: 5 : Value produced by BindingExpression is not valid for target property.; Value='UW.Entities.ProgramModel.UWProgram' BindingExpression:Path=; DataItem='RuntimeType' (HashCode=24995901); target element is 'DataGridCollectionViewSource' (HashCode=60976864); target property is 'Source' (type 'Object')

I don't know how to interpret this in a way that can let me find the responsible line of xaml. I can't even figure out what xaml file the error is coming from. Is there some way to get more information when these errors occur?

'UW.Entities.ProgramModel.UWProgram' is just a type - I don't know what the object being bound to is. I also have lots of DataGridCollectionViewSources in various bits of xaml, all who's property 'Source' is bound to something which may or may not have that type (again - no easy way to tell).

回答1:

If you do not know which binding fails

I would use the Snoop utility for this purposes. In short - at the top-left corner above the visual tree, you'll find a drop-down list which allows filtering visuals, just select Visuals with binding Error. See online documentation for more details.

If you know which binding fails

Sometime you know which binding fails but was not able to find a source fo the problem since binding is pretty tricky, for instance TemplateBindings, bindings which refer to a DataContext of another control, etc.. I found helpful putting a TextBlock which Text property is bound to the same binding source in this way you can see what exactly bound since TextBlock will display a type name of a bound object.

For instance you have following failed binding:

<ItemsControl ItemsSource="{Binding Parent.DataContext.ActiveItem.DataContext}" />

<!-- See what is bound, if failed - try previous level  -->
<TextBlock Text="{Binding Parent.DataContext}" />
<TextBlock Text="{Binding Parent.Inner.Items}" />
<TextBlock Text="{Binding Parent.Inner}" />

Useful links:

  • Debugging Data Bindings in a WPF or Silverlight Application
  • Nice trick using special DebugConverter which allows break a debugger whilst doing a binding, see Debugging WPF DataBinding article


回答2:

I have been happily using the wonderful snippet from 'Switch on the Code' to detect and report binding errors since it was first published in 2009...

http://www.switchonthecode.com/tutorials/wpf-snippet-detecting-binding-errors

edit: still works excellently on VS2012 (Sept 2013)

Update 25 Jan 2016

The link appears broken, so I'll paste in the relevant snippets...

using System.Diagnostics;
using System.Text;
using System.Windows;

namespace SOTC_BindingErrorTracer
{
    public class BindingErrorTraceListener : DefaultTraceListener
    {   //http://www.switchonthecode.com/tutorials/wpf-snippet-detecting-binding-errors
        private static BindingErrorTraceListener _Listener;
        public static void SetTrace()
        { SetTrace(SourceLevels.Error, TraceOptions.None); }
        public static void SetTrace(SourceLevels level, TraceOptions options)
        {
            if (_Listener == null)
            {
                _Listener = new BindingErrorTraceListener();
                PresentationTraceSources.DataBindingSource.Listeners.Add(_Listener);
            }
            _Listener.TraceOutputOptions = options;
            PresentationTraceSources.DataBindingSource.Switch.Level = level;
        }
        public static void CloseTrace()
        {
            if (_Listener == null)
            { return; }
            _Listener.Flush();
            _Listener.Close();
            PresentationTraceSources.DataBindingSource.Listeners.Remove(_Listener);
            _Listener = null;
        }
        private StringBuilder _Message = new StringBuilder();
        private BindingErrorTraceListener()
        { }
        public override void Write(string message)
        { _Message.Append(message); }
        public override void WriteLine(string message)
        {
            _Message.Append(message);

            var final = _Message.ToString();
            _Message.Length = 0;

            MessageBox.Show(final, "Binding Error", MessageBoxButton.OK,
              MessageBoxImage.Error);
        }
    }
}

And to set it up/initialize it...

namespace WpfListeningForTraceErrors
{
    /// <summary>
    /// Interaction logic for Window1.xaml
    /// </summary>
    public partial class Window1 : Window
    {
        public Window1()
        {
            BindingErrorTraceListener.SetTrace();
            InitializeComponent();
        }
    }
}


回答3:

You can add this to every control that binds

  PresentationTraceSources.TraceLevel="High" 

And run the program in debug, the detailed binding information will appear in your Output window. It may help a bit. You can also create a pass though converter to catch an error (catches the problem some times but not always). There are no good tools for debugging XAML in general that I am aware of.



回答4:

You can download a tool called Snoop that will allow you to debug bindings. It provides a view of your WPF applications visual tree higlighting any binding errors that it finds.

You can get some basic information about binding errors in the Output Window in Visual Studio. It will show the binding expression path error and the line on which the error occured.



回答5:

In VisualStudio goto Tools->Extentions and Updates->(download Output Enhancer). When you build your solution you will get the exact kind of error message you posted in Red color if there is a binding error.