#1,212 – Viewing WPF Trace Output Outside of Visual Studio

When you’re running a WPF application from within Visual Studio, you can view trace output in Visual Studio’s Output window. That is, you’ll see any trace output that you generate using Trace.WriteLine. This doesn’t work, however, if you’re not running in Debug mode or when you run your application outside of Visual Studio.

There’s a tool that you can use, however, to capture Trace output for a WPF application, even if it it’s a Release build and is running outside of Visual Studio.

The DebugView tool, available for download here, will display debug output for all applications in Windows. This includes .NET Trace output, which means that the application will display all trace output while your application is running.

Note that DebugView shows debug output for all applications, which means that you may need to filter out applications that you don’t care about. (See OutputDebugString call in the Win32 library).

Let’s say that we do the following in a Button_Click event:

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            Trace.WriteLine($"You clicked a button at {DateTime.Now.ToLongTimeString()}");
        }

We can now build and run the WPF application (i.e. after shutting down Visual Studio). Running DebugView, you can see the output.

#1,211 – Catching Exceptions Originating in Property Accessors

Post #1,210 explained that when data binding causes a property accessor to fire (either get or set) and an exception occurs, the exception will be ignored by the data binding layer. The exception gets caught internally and converted into a binding error that you normally don’t see.

We can use the technique described in #1,209 to to intercept this binding error and convert it back to an exception. This avoids the problem of these original exceptions never being seen.

Below is a complete example, setting us up with a NullReferenceException that comes out of a property set accessor. We wire up a trace listener that will catch this error and other binding errors.

First, we define a BindingErrorTraceListener class, which intercepts the binding errors by overriding the WriteLine method. In the snippet below, we simply throw a new exception that contains the entire text of the binding error. This will work for all binding errors (e.g. due to binding expression problems or due to exceptions coming out of property accessors).

    public class BindingErrorTraceListener : TraceListener
    {
        public override void Write(string s) { }

        public override void WriteLine(string message)
        {
            throw new Exception(message);
        }
    }

Next, we wire up the listener in our application’s startup logic. We also set up a handler for unhandled exceptions and display the body of the exception. (You could just as easily log the exception here).

    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)
        {
            MessageBox.Show(e.Exception.Message);
        }
    }

For existing WPF applications, this is all you need to do. All binding errors will now be converted to exceptions, caught and displayed. Some might argue that this should be standard fare for every WPF application. (Maybe not displaying the errors to the user, but at least logging them).

The snippets below are for a sample application, so that you can see this in action.

We start with a window that lets the user type in someone’s name then then displays the number of characters in the name.

<Window x:Class="WpfApp1.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:local="clr-namespace:WpfApp1" mc:Ignorable="d" Title="A ColorAnimation" Height="350" Width="525">
    
    <Grid Margin="10">
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition/>
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="Auto"/>
            <ColumnDefinition/>
        </Grid.ColumnDefinitions>
        
        <TextBlock Text="Enter text:"/>
        <TextBox Grid.Column="1" Margin="10,0" Text="{Binding YourTextqqqq, UpdateSourceTrigger=PropertyChanged}"/>

        <TextBlock Grid.Row="1" Margin="0,10" Text="Length:"/>
        <TextBlock Grid.Row="1" Grid.Column="1" Margin="0,10" Text="{Binding TextLength}"/>
    </Grid>
</Window>

In the code-behind, we simply wire up the DataContext of the window to a viewmodel.

    public partial class MainWindow : Window
    {
        public SomeViewModel ViewModel { get; set; }

        public MainWindow()
        {
            InitializeComponent();
            ViewModel = new SomeViewModel();
            this.DataContext = ViewModel;
        }
    }

Finally, we have the body of our viewmodel, where we make an attempt to call a method on a BobNotify object when the user types “Bob”. We haven’t initialized the object, so this will generate a null reference exception.

    public class SomeViewModel : INotifyPropertyChanged
    {
        private BobNotify _bobNotify;

        private string _yourText;
        public string YourText
        {
            get { return _yourText; }
            set
            {
                if (SetProp(ref _yourText, value))
                {
                    // E-mail Bob if someone types his name
                    // (but we forgot to initialize BobNotify object, so will get NullRefException here).
                    if (_yourText == "Bob")
                        _bobNotify.SendEmail(_yourText);

                    RaisePropertyChanged("TextLength");
                }
            }
        }

        public int TextLength
        {
            get
            {
                return string.IsNullOrWhiteSpace(_yourText) ? 0 : _yourText.Length;
            }
        }

        protected bool SetProp<T>(ref T backingField, T value, [CallerMemberName] string propName = null)
        {
            bool valueChanged = false;

            // Can't use equality operator on generic types
            if (!EqualityComparer<T>.Default.Equals(backingField, value))
            {
                backingField = value;
                RaisePropertyChanged(propName);
                valueChanged = true;
            }

            return valueChanged;
        }

        public event PropertyChangedEventHandler PropertyChanged = delegate { };

        private void RaisePropertyChanged(string propname)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propname));
        }
    }

When we put all of these pieces together and test the application, we see that when the user types “Bob”, we get the dialog popping up with the full text of the binding error. In the body of the error you can see the original NullReferenceException.

One interesting thing to note is the part saying target element is ‘TextBox’ (Name=”). The name is empty because in .xaml, we didn’t name the element. You often avoid naming XAML elements in WPF because you shouldn’t need to interact with the elements in your code-behind. However, naming elements can be useful in cases like this, where the name would normally be reported.

#1,210 – Exceptions in Property Accessors Can Be Ignored in Production Code

In the same way that binding errors are quietly swallowed in production code, exceptions originating in property getters or setters invoked as a result of WPF data binding can also be quietly ignored in production code.

Assume that we bind a TextBox.Text property to a string-based property in a ViewModel, as below. Note that when the data binding engine tries to set a property value of “Bob”, we’ll get a NullReferenceException.

        private BobNotify _bobNotify;

        private string _yourText;
        public string YourText
        {
            get { return _yourText; }
            set
            {
                if (SetProp(ref _yourText, value))
                {
                    // E-mail Bob if someone types his name
                    // (but we forgot to initialize BobNotify object, so will get NullRefException here).
                    if (_yourText == "Bob")
                        _bobNotify.SendEmail(_yourText);

                    RaisePropertyChanged("TextLength");
                }
            }
        }

        public int TextLength
        {
            get
            {
                return string.IsNullOrWhiteSpace(_yourText) ? 0 : _yourText.Length;
            }
        }

If we include this code in a release build and do nothing special to listen for binding errors, the exception will be quietly swallowed. The only hint that something went wrong is that the TextBlock that we bind TextLength to doesn’t get updated once we type the second “b” in “Bob”.

We can handle these sorts of errors in the same way that we did for other types of binding errors, by adding a binding error trace listener.