This posting is part of a series detailing how to write a custom Debugger Visualizer for Visual Studio.
Posts in the series:
- Writing A (ReadOnly) Custom Debugger Visualizer for Visual Studio
- Writing A Custom Debugger Visualizer for Non-Serializable Types or More Complex Objects
- Writing A Custom Debugger Visualizer using WPF for the UI
- Modifying The Live Object in Your Custom Debugger Visualizer for Visual Studio
- Installation, Limitations, and Security Considerations for Your Custom Debugger Visualizer for Visual Studio
I've also given a talk on this topic: Putting the Visual into the Visual Studio Debugger.
You can find code samples to go along with this series in my DebugVisualizer
GitHub repository.
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.