Writing A Custom Debugger Visualizer using WPF for the UI

This post builds upon the first post in the series Writing A (ReadOnly) Custom Debugger Visualizer for Visual Studio. Please at least skim through that post to understand the topics in this one.

Using WPF for the UI

Ok, so far my UIs have been pretty basic, but as I start to visualize more complex object types, I'm going to need more complex UIs. And personally, I find that hard to do with WinForms. Plus, I'd rather use MVVM-style UI binding instead of the code-behind style typical with WinForms. So, I want to use WPF for my UI instead of WinForms.

Thankfully, this is super easy to do!

I'll use the same ViewModel and VizualizerObjectSource as I did for my WinForms visualizer, but on the Visual Studio side, I'll have a different UI and a different Visualizer class:

The UI

Obviously, the UI will be WPF-based now. I'll use DataContext binding in my XAML to bind directly against my ViewModel class.

<UserControl x:Class="TotallyRealApp.DebuggerVisualizer.WebException.WebExceptionVisualizerControl"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
            xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
            xmlns:local="clr-namespace:TotallyRealApp.DebuggerVisualizer.WebException"             
            mc:Ignorable="d" 
            d:DesignHeight="500" d:DesignWidth="500"             
            MinWidth="500" MinHeight="500" HorizontalAlignment="Stretch" VerticalAlignment="Stretch"
            d:DataContext="{d:DesignInstance Type=local:WebExceptionViewModel, IsDesignTimeCreatable=False}"
            Padding="5" Margin="5">
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="*" MinWidth="500"/>
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto" />
            <RowDefinition Height="Auto" />
            <RowDefinition Height="Auto" />
            <RowDefinition Height="Auto" />
            <RowDefinition Height="*" />
        </Grid.RowDefinitions>

        <StackPanel Orientation="Horizontal" Margin="0 5" Grid.Row="0">
            <Label Margin="0 0 5 0" Padding="0" FontWeight="Bold">Message:</Label>
            <TextBlock TextWrapping="Wrap" Text="{Binding Path=Message, Mode=OneWay}" Height="auto" />
        </StackPanel>           

        <Label  Grid.Row="1" Margin="0 5" Padding="0" FontWeight="Bold">Stack Trace:</Label>

        <ScrollViewer Grid.Row="2"  VerticalScrollBarVisibility="Visible" HorizontalScrollBarVisibility="Auto">
            <TextBlock Width="Auto" TextWrapping="Wrap" Text="{Binding Path=StackTrace, Mode=OneWay}"></TextBlock>
        </ScrollViewer>

        <Label Margin="0 0 5 0" Padding="0 5" FontWeight="Bold" Grid.Row="3">Raw Response:</Label>

        <ScrollViewer HorizontalAlignment="Stretch" VerticalAlignment="Stretch" VerticalScrollBarVisibility="Visible" HorizontalScrollBarVisibility="Auto" Grid.Row="4">
            <TextBlock TextWrapping="NoWrap" Text="{Binding Path=Response.RawResponse, Mode=OneWay}" Width="Auto"></TextBlock>
        </ScrollViewer>


    </Grid>
</UserControl>

The Visualizer

The other change that's needed to use WPF is to the Visualizer. Instead of using the passed-in IDialogVisualizerService to show a dialog, we'll create an instance of a WPF Window, put our WPF UserControl on it, and show that window.

public class WpfWebExceptionVisualizer : DialogDebuggerVisualizer
{
    protected override void Show(IDialogVisualizerService windowService, IVisualizerObjectProvider objectProvider)
    {          
        if (objectProvider == null)
            throw new ArgumentNullException(nameof(objectProvider));

        // Get the object to display a visualizer for.
        //       Cast the result of objectProvider.GetObject() 
        //       to the type of the object being visualized.
        var data = objectProvider.GetObject() as WebExceptionViewModel;

        // Display your view of the object.                       
        var vizControl = new WebExceptionVisualizerControl { DataContext = data };

        // set the attributes of WPF window
        var win = new Window
        {
            Title = "WPF Web Exception Visualizer",
            MinWidth = 500,
            MinHeight = 500,
            Padding = new Thickness(5),
            Margin = new Thickness(5),
            WindowStartupLocation = WindowStartupLocation.CenterScreen,
            Content = vizControl,
            VerticalContentAlignment = VerticalAlignment.Stretch,
            HorizontalContentAlignment = HorizontalAlignment.Stretch
        };

        win.ShowDialog();
    }
}

Make sure to take a look at the other posts in my Debugger Visualizer series to improve upon your visualizer.