#1,209 – Catching Data Binding Errors Part 2
May 20, 2017 2 Comments
In Part 1, I described how to use a TraceSource to intercept data binding errors. Below, we convert these binding errors into exceptions. You then can know that the error will get reported at runtime and you can catch and handle the exception as you like.
(Code below is inspired by WpfBindingErrors project and Jason Bock’s blog post).
Building on the code in the earlier post, we modify the WriteLine method to parse the resulting error message and build up a custom exception type.
public class BindingErrorException : Exception { public string SourceObject { get; set; } public string SourceProperty { get; set; } public string TargetElement { get; set; } public string TargetProperty { get; set; } public BindingErrorException() : base() { } public BindingErrorException(string message) : base(message) { } } public class BindingErrorTraceListener : TraceListener { private const string BindingErrorPattern = @"^BindingExpression path error(?:.+)'(.+)' property not found(?:.+)object[\s']+(.+?)'(?:.+)target element is '(.+?)'(?:.+)target property is '(.+?)'(?:.+)$"; public override void Write(string s) { } public override void WriteLine(string message) { var xx = new BindingErrorException(message); var match = Regex.Match(message, BindingErrorPattern); if (match.Success) { xx.SourceObject = match.Groups[2].ToString(); xx.SourceProperty = match.Groups[1].ToString(); xx.TargetElement = match.Groups[3].ToString(); xx.TargetProperty = match.Groups[4].ToString(); } throw xx; } }
As before, we attach a listener at startup. We also catch unhandled binding exceptions and display a MessageBox.
public partial class App : Application { protected override void OnStartup(StartupEventArgs e) { base.OnStartup(e); PresentationTraceSources.Refresh(); PresentationTraceSources.DataBindingSource.Switch.Level = SourceLevels.Error; PresentationTraceSources.DataBindingSource.Listeners.Add(new BindingErrorTraceListener()); DispatcherUnhandledException += App_DispatcherUnhandledException; } private void App_DispatcherUnhandledException(object sender, System.Windows.Threading.DispatcherUnhandledExceptionEventArgs e) { var bex = e.Exception as BindingErrorException; if (bex != null) { MessageBox.Show($"Binding error. {bex.SourceObject}.{bex.SourceProperty} => {bex.TargetElement}.{bex.TargetProperty}"); } } }
For a bad property name that leads to a binding error, we then get a nice little error.