|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Announcements
Want a new Job?
Chapters
Services
Feature Zones
|
A meaningful way to visualize variables in the debuggerThe Autos, Locals and the four watch windows provided by the Visual Studio IDE allow you to inspect and modify variable values. However, for viewing complex objects having many properties and fields, this is not the friendliest interface to inspect values. The main issue is the lack of an overall picture. For example, for a Fortunately, debuggers in Visual Studio 2005 and Visual Studio 2008 have a feature called Debugger Visualizer which allows an alternative and friendly way to view complex objects. A good example of this is the DataSet Visualizer which shows the actual data of the While working with WPF, I found it a little painful that there was no easy way to visualize the UI hierarchy while debugging. Then, I found a neat debugger visualizer that visualized the WPF visual tree, by David Sleeckx. After using that for some time, it struck to me that it will be neat to have a XAML visualizer which will allow visualizing the XAML representation of an object and also allowing modifying the object by modifying the XAML. I personally have used the visualizer extensively to modify templates in a debugging session. This allows me to test things without cancelling the debugging session or starting a new build. In the next section, I will take you on a guided tour of the visualizer and we will see it in action. Using the XamlVisualizer - A guided tourIf you have not already downloaded and installed the visualizer, go ahead and do so as per the instructions in the Download and Installation section. Assuming you have followed the steps in the Download and Installation section correctly, you are now ready to use the visualizer. Let's start with a quick debugging session. I have used VS 2008 to develop this step by step tutorial, but the instructions are equally valid if you have VS 2005 and the Visual Studio Tools for Orcas installed. First, let's start off by creating a new WPF project. For the sake of this tutorial, we will create a new WPF application in C#. Let's name the project XamlVisualizerTest as shown in the screenshot below. Also, notice the combo box in the upper right corner whose selected value is ".NET Framework 3.0". This is the new multi-targeting feature of VS 2008. When you select .NET Framework 3.0, you indicate that you will like to use the WPF/WCF/WF technologies which are available in .NET Framework 3.0 but you don't want to use the .NET Framework 3.5 features such as LINQ. What VS 2008 does in such a case is that it does not add references to LINQ assemblies. But you are free to use C# 3.0 features such as anonymous classes, lambda expressions, and auto implemented properties - these features are not specific to LINQ or .NET Framework 3.5.
As a courtesy, the wizard creates Window1.xaml, Window1.xaml.cs, App.xaml, and app.xaml.cs (though in real world apps, I have to always delete the Window1.xaml file, so it is more of a pain than a courtesy). Open the
Notice the magnifying glass icon on the extreme right in the Value column for the variable
Notice that the XAML code is not the same as the XAML you specified in the Window1.xaml file. This is because the XAML shown by the XAML Visualizer is the run-time representation of the object. So if a property specified in XAML gets modified programmatically, then the XAML visualizer will show the programmatically modified value. Also, notice that the element name is Viewing more complex XAML contentA common task when working in WPF is to use control templates. Even if you don't specify a control template, a control inherits a template automatically from the theme. The default control templates for controls used by WPF are available for all the themes supported by WPF with the Windows SDK samples. But in this section, we will see how we can get the markup of a template using the XAML Visualizer. To view the control template, we need to have more interesting content in our window. So, let's modify Window1.xaml to include a <Window x:Class="XamlVisualizerTest.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="300" Width="300">
<Grid>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition Height="40" />
</Grid.RowDefinitions>
<Button Grid.Row="1" HorizontalAlignment="Right" Margin="0,9,9,11"
Name="button1" Width="75">Button</Button>
</Grid>
</Window>
Let's launch the debugger again, and when the debugger hits the breakpoint in
As you can see in screenshot, the XAML for the default template in all its details is shown in the XAML Visualizer window. Also, notice that the Replace button is active, which gives us something to do in the next section. Replacing the XAML contentOne nice feature of modern debuggers is that they allow the values of variables to be modified during the debugging process. The same ability is also available in the XAML Visualizer. You can modify the XAML code in the visualizer window and see the effects in the application being debugged. To try it out, let's modify the XAML content of
The change is highlighted in the above screenshot. We change the
We managed to change the color to blue without modifying the main application code. It's all between the debugger and debuggee, the main code still remains unmodified. If you stop the debugger and re-run the application, then the button's appearance will revert back. Replacing the XAML is powerful but...Let me start this section by saying that XAML replacement will not always work. In this section, we will understand why and when it will not work. Let's run our sample app again in the debugger, and break in the
You will expect that the button text will change once you click the Replace button. But alas, this does not happen. You will see that the original text remains. Is this a bug? Although this behavior is not expected on the outset, if we give it a more careful thought, we will realize that the visualizer did exactly what it was supposed to do. It replaced the How Visualizers work?In this section, I will quickly go through the internal working of the XAML Visualizer. XAML Visualizer has three main classes as shown below:
The protected override void Show(IDialogVisualizerService windowService,
IVisualizerObjectProvider objectProvider)
{
//The stream to which the dat ais written can be obtained by calling GetData
Stream dataStream = objectProvider.GetData();
//Replace displayForm with your own custom Form or Control.
using (XamlVisualizerForm displayForm = new XamlVisualizerForm())
{
displayForm.XamlText = new StreamReader(dataStream).ReadToEnd();
displayForm.IsObjectReplaceable = objectProvider.IsObjectReplaceable;
if (windowService.ShowDialog(displayForm) == DialogResult.OK)
{
//After the dialog is shown the user
//may click replace to replace the object
MemoryStream replacementDataStream = new MemoryStream();
using (XmlWriter xmlWriter =
XmlTextWriter.Create(replacementDataStream))
{
xmlWriter.WriteRaw(displayForm.XamlText);
}
replacementDataStream.Seek(0, SeekOrigin.Begin);
//Replace the object in the debuggee
objectProvider.ReplaceData(replacementDataStream);
}
}
}
The /// <summary>
/// This function is used to write a representation of the object to a stream.
/// The visualizer can then use the data to display
/// the object. The default implementation
/// of this function serailzes the object using
/// Binary formatter. But in our implementation we will
/// write the contents of the object as Xaml to the stream
/// </summary>
/// <param name="target">The target object</param>
/// <param name="outgoingData">The stream
/// where the XAML needs to be written to</param>
public override void GetData(object target, System.IO.Stream outgoingData)
{
//Although the XamlWriter class has a member that writes to the
//stream, we use an XmlWriter. This is because we want the output to be
//indented.
XmlWriterSettings settings = new XmlWriterSettings();
settings.OmitXmlDeclaration = true;
settings.Indent = true;
settings.IndentChars = " "; //3 spaces
settings.NewLineOnAttributes = true;
using (XmlWriter writer =
XmlWriter.Create(outgoingData, settings))
{
XamlWriter.Save(target, writer);
}
}
It is this stream which is obtained by the /// <summary>
/// This method is called on the debuggee side. The purpose of this method is to
/// take the target object that is being visualized and a stream and return an
/// object that can replace the object being visualized. In our implementation
/// we simply use the XamlReader object to reconstruct
/// an object from the Xaml content
/// provided in the stream.
/// </summary>
/// <param name="target">The object being visualized</param>
/// <param name="incomingData">The stream that
/// contains data sent from the debugger</param>
/// <returns>An object that replaces the target object</returns>
public override object CreateReplacementObject(object target,
System.IO.Stream incomingData)
{
return XamlReader.Load(incomingData);
}
It is no surprise that we are using //Apply XamlVisualizer Visualizer to a WPF Visual
[assembly: DebuggerVisualizer(typeof(XamlVisualizer.XamlVisualizer),
typeof(XamlVisualizer.XamlVisualizerObjectSource),
Target=typeof(Visual), Description = "XAML Visualizer")]
//Apply XamlVisualizer Visualizer to a WPF Style
[assembly: DebuggerVisualizer(typeof(XamlVisualizer.XamlVisualizer),
typeof(XamlVisualizer.XamlVisualizerObjectSource),
Target = typeof(Style), Description = "XAML Visualizer")]
//Apply XamlVisualizer Visualizer to templates
[assembly: DebuggerVisualizer(typeof(XamlVisualizer.XamlVisualizer),
typeof(XamlVisualizer.XamlVisualizerObjectSource),
Target = typeof(FrameworkTemplate), Description = "XAML Visualizer")]
In the above code, we indicate that we want to use the XAML Visualizer to visualize WPF Visuals, Styles, and Templates. If you want to add more types (for example, a //Apply XamlVisualizer Visualizer to documents
[assembly: DebuggerVisualizer(typeof(XamlVisualizer.XamlVisualizer),
typeof(XamlVisualizer.XamlVisualizerObjectSource),
Target = typeof(FlowDocument), Description = "XAML Visualizer")]
You can add this attribute to all Installing the VisualizerTo install the Visualizer:
UpdateI started writing this article about two months back, though I have been using the visualizer for a long time. By the time the article got posted, Josh Smith had posted Woodstock for WPF, which is similar to the WPF tree visualizer by David Sleeckx. Both XAML Visualizer and Woodstock can be used together.
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||