#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.

 

#1,209 – Catching Data Binding Errors Part 2

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.

 

#1,208 – Catching Data Binding Errors Part 1

In WPF, data binding errors by default are quietly swallowed, rather than throwing an exception.

Happily, there is a TraceSource that we can use to intercept all binding errors. All data binding errors will go through this trace source and we can therefore add a TraceListener to the trace source’s Listeners collection in order to intercept the error.

We start by creating a simple class deriving from TraceListener that overrides Write and WriteLine methods. These methods will be invoked when messages come from the trace source. Note that we don’t yet do anything useful with these messages, but just dump them to standard trace output (to prove to ourselves that we got them).

   public class BindingErrorTraceListener : TraceListener
    {
        public override void Write(string message)
        {
            Trace.WriteLine(string.Format("==[Write]{0}==", message));
        }

        public override void WriteLine(string message)
        {
            Trace.WriteLine(string.Format("==[WriteLine]{0}==", message));
        }
    }
}

We can now wire our listener into the standard data binding trace source. Below, we do this at application startup.


    public partial class App : Application
    {
        protected override void OnStartup(StartupEventArgs e)
        {
            base.OnStartup(e);

            PresentationTraceSources.DataBindingSource.Switch.Level = SourceLevels.Error;
            PresentationTraceSources.DataBindingSource.Listeners.Add(new BindingErrorTraceListener());
        }
    }

At this point, we’re not doing anything with the binding errors. But if you watch the output window, you’ll see that we’re now capturing them.

Next time, we’ll look at converting these errors into exceptions that you can catch.

#1,207 – Data Binding Can Fail Quietly in Production Code

By default, if there’s a problem in how you set up data binding in WPF, the user of the application will never see the binding errors. An exception occurs internally for the binding error, but the WPF application won’t crash or report the exception.

Let’s say that we have that we have an application the includes the following properties in an object that we bind to (i.e. the object that we set the DataContext of a window to). (Using SetProp from post #1,205).

        private string _yourText;
        public string YourText
        {
            get { return _yourText; }
            set
            {
                if (SetProp(ref _yourText, value))
                {
                    RaisePropertyChanged("TextLength");
                }
            }
        }

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

Now let’s say that we have the following XAML fragment (assume in a Window whose DataContext is set to a class containing the properties shown above).

        <TextBlock Text="Enter text:"/>
        <TextBox Grid.Column="1" Margin="10,0" Text="{Binding YourText, UpdateSourceTrigger=PropertyChanged}"/>

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

Note the error–we spelled the TextLength property incorrectly, so binding for this TextBlock will fail.

If we just build and run the application, we won’t get an exception and the application will run fine. It just won’t bind to TextLength.

If you run the application in the Visual Studio debugger and pay attention to the Output window, you’ll see the error reported there. But WPF swallows this error and the application runs fine.

#1,206 – Changing Color of Custom Circular Progress

A couple of earlier posts (#1,155 and #1,156) demonstrated how to create a simple custom control that displays progress in a circular fashion. A reader of the blog asked how you would change the color of the progress indicator when it got to a certain value. The example below shows how to do that.

Below is the code for the indicator itself. This matches post #1,156 except that we’ve removed the static constructor that overrides the stroke and fill color of the indicator.

    public class CircularProgress : Shape
    {
        // Value (0-100)
        public double Value
        {
            get { return (double)GetValue(ValueProperty); }
            set { SetValue(ValueProperty, value); }
        }

        // DependencyProperty - Value (0 - 100)
        private static FrameworkPropertyMetadata valueMetadata =
                new FrameworkPropertyMetadata(
                    0.0,     // Default value
                    FrameworkPropertyMetadataOptions.AffectsRender,
                    null,    // Property changed callback
                    new CoerceValueCallback(CoerceValue));   // Coerce value callback

        public static readonly DependencyProperty ValueProperty =
            DependencyProperty.Register("Value", typeof(double), typeof(CircularProgress), valueMetadata);

        private static object CoerceValue(DependencyObject depObj, object baseVal)
        {
            double val = (double)baseVal;
            val = Math.Min(val, 99.999);
            val = Math.Max(val, 0.0);
            return val;
        }

        protected override Geometry DefiningGeometry
        {
            get
            {
                double startAngle = 90.0;
                double endAngle = 90.0 - ((Value / 100.0) * 360.0);

                double maxWidth = Math.Max(0.0, RenderSize.Width - StrokeThickness);
                double maxHeight = Math.Max(0.0, RenderSize.Height - StrokeThickness);

                double xStart = maxWidth / 2.0 * Math.Cos(startAngle * Math.PI / 180.0);
                double yStart = maxHeight / 2.0 * Math.Sin(startAngle * Math.PI / 180.0);

                double xEnd = maxWidth / 2.0 * Math.Cos(endAngle * Math.PI / 180.0);
                double yEnd = maxHeight / 2.0 * Math.Sin(endAngle * Math.PI / 180.0);

                StreamGeometry geom = new StreamGeometry();
                using (StreamGeometryContext ctx = geom.Open())
                {
                    ctx.BeginFigure(
                        new Point((RenderSize.Width / 2.0) + xStart,
                                  (RenderSize.Height / 2.0) - yStart),
                        true,   // Filled
                        true);  // Closed
                    ctx.ArcTo(
                        new Point((RenderSize.Width / 2.0) + xEnd,
                                  (RenderSize.Height / 2.0) - yEnd),
                        new Size(maxWidth / 2.0, maxHeight / 2),
                        0.0,     // rotationAngle
                        (startAngle - endAngle) > 180,   // greater than 180 deg?
                        SweepDirection.Clockwise,
                        true,    // isStroked
                        false);
                    ctx.LineTo(new Point((RenderSize.Width / 2.0), (RenderSize.Height / 2.0)), true, false);
                }

                return geom;
            }
        }
    }

Next is a snippet from the code-behind for a main window. This is just a click handler for a button that updates a property. (Note the use of SetProp method from post #1,205)

        private double _pctComplete = 0.0;
        public double PctComplete
        {
            get { return _pctComplete; }
            set { SetProp(ref _pctComplete, value); }
        }

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            PctComplete = 0.0;

            DispatcherTimer timer = new DispatcherTimer();
            timer.Tick += (s, ea) =>
            {
                PctComplete += 1.0;
                if (PctComplete >= 100.0)
                    timer.Stop();
            };
            timer.Interval = new TimeSpan(0, 0, 0, 0, 150);  
            timer.Start();
        }

We then have a XAML fragment, where we define an instance of the progress indicator. We also set up a data trigger to set the Stroke and Fill properties to change color when they reach a certain level.

    <Window.Resources>
        <loc:GreaterThanConverter x:Key="greaterThanConverter"/>
        
        <Style x:Key="progChangeColor" TargetType="loc:CircularProgress">
            <Setter Property="Stroke" Value="Red"/>
            <Setter Property="Fill" Value="Red"/>
            <Style.Triggers>
                <DataTrigger Binding="{Binding PctComplete, Converter={StaticResource greaterThanConverter}, ConverterParameter=75}" Value="True">
                    <Setter Property="Stroke" Value="Green"/>
                    <Setter Property="Fill" Value="Green"/>
                </DataTrigger>
            </Style.Triggers>
        </Style>
    </Window.Resources>
    
    <StackPanel>
        <loc:CircularProgress
            Style="{StaticResource progChangeColor}"
             Height="100" Width="100" Margin="5"
             Value="{Binding PctComplete}"
             HorizontalAlignment="Center"/>
        <ProgressBar Maximum="100"
                 Value="{Binding PctComplete}"
                 Height="25" Margin="10"/>
        <Button Content="Start Timer" Click="Button_Click"
            HorizontalAlignment="Center"
            Padding="12,7"/>
    </StackPanel>

Note that we’re making use of a value converter that takes a value in (e.g. PctComplete) and outputs True when that value passes a certain point (e.g. 75). Here’s the code for that converter:

    public class GreaterThanConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            return ((double)value) > double.Parse(parameter as string);
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }

When everything is wired up and we run this, we see that the indicator starts out red.

And it then turns green when progress gets past 75%.