Mole 2010 is Now Available

If you are using Visual Studio 2010 and would like to use the Mole debugging tool, please visit http://www.molosoft.com to get your copy today. Mole 2010 makes debugging easier.
Mole v4 for Visual Studio - With Editing Released
All versions of Mole have been replaced by Mole v4 for Visual Studio.
Please refer to this article for the latest information and code: Mole v4 for Visual Studio - With Editing.
This article is here for informational purposes. The downloads have been removed. Please download and use Mole v4 for Visual Studio - With Editing. Thank you!
Authoring
No question about it, Mole was a team effort.
Karl created Mole and wrote this article. Josh Smith and Karl developed Woodstock and Mole during the same time frame, and were able to draw from each other's efforts. Woodstock acted as a prototype, or proof-of-concept, upon which the design and some algorithms in Mole are based. Mole adds a rich array of user-friendly, useful, and refined additions to the core functionality chiseled out in Woodstock.
I really appreciate working together with Josh Smith on critical sections of the code. We have gone back and forth with our projects trying to deliver tools that developers will utilize.
Introduction
Mole is a multifunction Visual Studio Visualizer which allows you to inspect elements in the WPF visual tree, as well as all properties of those elements..
The focus of this article is to introduce Mole, explain how to use it, and to introduce techniques for creating and debugging visualizers.
Mole's Feature Set
- View the structure of a WPF visual tree in a treeview control
- View all properties of any element in a visual tree
- For properties that are collections, view the values inside these collections
- View an image which represents the element being visualized
- View run-time XAML in an HTML viewer for an element
- Multithreaded, lazy loading for fast performance
- Persisted application state, and reloads settings from a previous Mole session
- Search for properties and property data values in various ways
- Configure which properties to view for any element/control
Background
There are a growing number of third party development tools for WPF developers. In addition, there have been very good articles recently posted on CodeProject presenting visualizers for WPF. When a great friend and coauthor Josh Smith wrote Woodstock for WPF a few weeks ago, I got pretty excited about how Visual Studio Visualizers that target WPF can really assist developers. I started making a list of features I wanted and began working on Mole.
Mole was my first visualizer and first real WinForms program I've done with .NET 2.0. I spent most of my time with WPF, ASP.NET, SQL Server, and Windows Services. Starting from scratch would prove to be challenging at times.
Mole grew alongside Woodstock as it was being developed and refined. Josh and I worked hard to develop fast performing visualizers. We both tried some crazy things during this process of refinement, some of these I wouldn't post on a billboard.
To give you a comparison of what we were up against from a data loading perspective, consider the Text Visualizer which ships with Visual Studio. It allows you to view long strings in a multiline TextBox
. Text Visualizer opens quickly and displays the string.
Mole displays an entire visual tree and over a hundred properties in a DataGridView
for any object selected in the TreeView
! Let's face it, the visualizer needs to load fast or it won't get used. What you'll see in this article is a highly refined visualizer which runs lightning fast. When running Mole in stress tests with absurdly large visual trees (over 10,000 elements), it was able to open in less than a second. Bearing in mind that most sane developers would never create visual trees of that size, it is safe to say that Mole is fast enough to be usable by the most impatient developers out there.
Where did the name Mole come from? The original name was Lucy, another member of the Peanuts gang. After a possible legal problem with using cartoon images in our visualizers was brought to light, I decided to change the name and colors, and came up with Mole and the earth colors. Moles love to dig. This Mole burrows around your visual tree and returns the requested information.
Being a fan of Business Intelligence applications and Drill Through or Drill Back, I wanted to give my visualizer some Drill Through capabilities. That is where the idea to be able to view property data that is stored in collections came from. Ask yourself, how many times have you been using the Visual Studio debugger and come upon a property that has its values stored in a collection and you can't see the values without having to do some more typing or supplying an indexer to see the data? Not with Mole. If the property stores its data in a collection, just click on the collection icon and all the values in the collection will be displayed. In testing, I've viewed trigger collections, row and column collections, and items collections that are custom classes, just to name a few. You can also see collection data in the run-time XAML viewer.
If you are debugging and perform a Quick Watch on a ComboBox
, 99% of the time you want to view the SelectedValue
, SelectedIndex
, Selected
... properties, right? Those other 130 properties I really never look at. So I added in the ability to select "favorite properties" by Framework type. That way, you can view just the properties for that type that you usually want to view. With the click of the mouse, you can toggle showing just favorites or all properties. These favorites are persisted so that you'll have them the next time the visualizer opens.
Installation
There are a number of options available to you for getting Mole installed on your machine. You can just install Mole and be Molenating, or you can download the source, build and install your build.
Mole has been tested on x64 and x32 systems, Vista and XP.
Standalone Install
- Download either MoleVisualizer_VS_2005_Update.zip or MoleVisualizer_VS_2008_Update.zip by clicking on the links here or at the top of this article.
- Save and unzip.
- Copy the files to one of the following directories:
- vs install path\Common7\Packages\Debugger\Visualizers
- My Documents\Visual Studio 2005\Visualizers {VS2005}
- My Documents\Visual Studio 2008\Visualizers {VS2008}
Source Code Install
I have provided the source for both VS2005 and VS2008. The only difference is the reference to Microsoft.VisualStudio.DebuggerVisualizers.DLL. For VS2005, the file version is 8.0.0.0, and for VS2008, the file version is 9.0.0.0.
Visual Studio Visualizers and XBAPs
One big advantage Mole and Woodstock have over some other tools is that you can use them to debug XBAP applications. Here is what you need to do to enable that:
- Right-click on the XBAP project in Solution Explorer and open the Properties page.
- Under the Security tab, select the "This is a full trust application" radio button.
- Be sure to set it back later on to Partial Trust in order to properly test deployment.
Thanks to Josh Smith and CodeProject member "ivolved" for this tip!
Using Mole
Mole is opened just like any other Visual Studio Visualizer, you click on the small magnifying glass icon, and this displays the visualizers lists, and then you select the visualizer you want to use. Mole is programmed to show up in the visualizers list when your mouse is over an object that is of type DependencyObject
. This snapshot was taken from the code window. You can also open visualizers from the Watch windows.

When Mole opens, it looks like this. There is a 600px image width restriction here at CodeProject. I reduced this image from the default width of 1024 to 600. I will cover each element in detail with full size images. When you resize Mole, the window persists its size, so on your next Mole session, the window will be the same size as you left it.

Element Tree - Mole's Garden

The Mole's Garden contains a TreeView
which displays the current visual tree of the WPF application being debugged. The TreeView
initially selects the object you selected in Visual Studio. The TreeNode
text is formatted as follows: Element Type - Element Name (Count Of Descendants).
Some nodes are not assigned names and some nodes do not have any child nodes associated with them. Notice the ListBox
named lbTest
has 1,111 items in it. Mole's Garden has a minimum width set so that the buttons beneath it will always be visible.
Elements are displayed in one of four colors. White is an unselected element. Light Gray is the selected element when the TreeView
has lost focus. Blue is the selected element when the TreeView
has focus. Moccasin is the initially selected object you moused over in Visual Studio.
The Light Brown 4 pixel line separating the two TabControl
s is a GridSplitter
. You may size the two regions. The size of the two panels is persisted when the size is changed so that the panels will be displayed the same when Mole is reopened.
The Select Initial button will select the object that you initially selected in Visual Studio. The Expand All button will expand all TreeNode
s in the entire TreeView
. The Collapse All button will collapse all TreeNode
s in the entire TreeView
. The Expand Down button will expand all TreeNode
s that are children of the currently selected TreeNode
. The Collapse Down button will collapse all TreeNode
s that are children of the currently selected TreeNode
.
Selected Element Tab Header

The selected element TabControl
has four TabPage
s.
The label below the Element Properties TabPage
heading is formatted as follows: [Object Type] [Has Favorites] [Object Name] [location loaded from].
Two of these need some explanation.
The [Has Favorites] text will appear if the selected element Framework Type has favorites associated with it. This is useful to remind you that this type has favorites associated with it.
[location loaded from] informs you whether the data was fetched from the process being debugged or read from the local cache. Data from the Properties tab and Visual tab is lazy loaded. The data is only loaded when the element is selected in the TreeView
and the tab page for that type of data is visible. The Visual Studio Visualizer architecture allows for two way conversations to take place across process boundaries, by using .NET Remoting. Mole takes full advantage of this technology, and only requests the data the users want to display. This lazy loading design drastically reduces the time it takes for Mole to load up.
Element Properties Grid

The Element Properties grid displays each of the selected item's properties. Columns with an underlined header text can be sorted by clicking on the column header. Like many features in Mole, the selected column sort is persisted between Mole debugging sessions. It is very easy to add more columns to this grid, so any suggestions from the community for more data to view are welcome.
When the help icon is clicked, it opens Google.com using your default browser and sets the query string to search for the property name and selected item type.
The Favorites column (Fav) indicates if this property is one of your favorites for the selected type. You may select or deselect favorites by clicking the checkbox. See the information below for a full explanation of the favorites feature.
The Category Name column is the name of the category assigned to it on the property declaration with the Sysem.ComponentModel.Category
attribute. To see an example of this attribute, look at the MoleTabControl.vb file in the solution source.
Value Source identifies the source for the property value. Only dependency properties can have a value source. If you are not familiar with the idea of value sources, please read up on the topic at MSDN BaseValueSource Enumeration.
The rightmost column, Is DP, identifies whether this property is a dependency property or not.
If a property stores its values in a collection and the collection actually contains items, the collection icon will display in the Coll column. When this icon is clicked, a modal window will open with a grid containing all the values of all the items in the collection. The image below displays the collection from the grid's Children
property.

Search

Mole allows you to search and filter the properties displayed. Mole searches are logical AND searches. If you have more than one search condition applied, then the property must meet both conditions in order to be displayed.
- The "Select Search Location" combobox allows you to select where and how you want the search text to be used. The search is conducted as you type in your search text.
- The "Show All" button clears any searching/filtering you have performed so that you can view all of the properties.
- The "Show Attached Properties" checkbox toggles the display of properties that are attached properties.
- The "If Has Favorites, Only Show Favorites" checkbox toggles the "favorite properties" display behavior. If checked and the selected element's type has one or more favorites assigned, then only properties assigned as favorites will be displayed. The beauty of this technique is that it permits you to leave this checkbox checked all the time, and when you select a type which has favorites, the displayed properties will only be those that you want. If the selected element's type has no favorite properties associated with it, then you will see all of that element's properties. After using Mole for a day, you'll have your favorites all established.
- The "If Has Collections, Only Show Collections" checkbox works the same as the above checkbox, except its logic is applied to properties with collections.
The Molenator's Blog link will take you to my blog. I will establish a special section on my blog for Mole and future visualizers.
Element Visual

The "Element Visual" tabpage displays an image of the selected element. The above image is from my RoutedEvent visual trace program. The image is lazy loaded, and the label under the Elements Visual header indicates where the image was loaded from, cache or fetched.
The displayed image can easily be copied to the Windows Clipboard by clicking on the "Copy Image" button.
This tab is pretty cool because it gives you insight into how the various elements in the visual tree participate in the rendering process. You can select this tab to display it, then click on an item in the element tree, and press the arrow key and go up or down the treeview's nodes to see what each element looks like. The "Copy Image" button makes it super easy to get snapshot images and copy them to other documents, emails, etc.
Element XAML
Expanded View

Compressed View

The "Element XAML" tabpage displays the run-time XAML which was transformed into HTML and loaded in the WebBrowser
control. The label under the WebBrowser
control follows the format of the other two tabpages.
The 'Font +' and 'Font -' buttons allow you to change the font size of the displayed text. This setting is also persisted between Mole sessions.
The two radio buttons allow you to select the format for the displayed XAML, expanded or compressed. This setting is also persisted between Mole sessions.
You may right-click the WebBrowser
control to access the copy, print, and view source functions.
This tabpage took longer to write than any other section of code. I really wish Microsoft would expose the default XSLT object which the WebBrowser
control uses internally, or just add a public method like RenderXML
, and the control would just perform the transformation like it does when it opens a file. This would make this control so much easier to use. At any rate, I downloaded a defaultss.xslt and edited it to get the above transformation. This file is in the solution source, and is also an embedded resource.
This tabpage is cool because if the element contains collections, those collections will be displayed here. I have loaded 20,000 items into a ListBox
and viewed the XAML for them in this XAML viewer.
Favorites

The Favorites tabpage presents a treeview of your favorite properties, grouped by Framework type.
Limitations
So far, the only limitation I've run into is the Element XAML. Under certain circumstances, the System.Windows.Markup.XamlWriter.Save
function can throw a StackOverFlow Exception or a GenericTypeSerialization Exception. This program has no control over this. The StackOverFlow will be reported in a message box and the visualizer will close. Just reopen it and don't select that element and view its XAML.
These two exceptions are thrown on the other side of the remoting conversation that handles data transfer requests. Once its stack is corrupted, that process must be terminated, thus ending our visualizer session.
You would get these same exceptions in your own code if you called System.Windows.Markup.XamlWriter.Save
and passed this same dependency object.
Mole & Visualizers 101
Before going any further, please get some background on visualizers. Once you have the basics, the rest is just plain fun!
The first article I read was Creating Debugger Visualizers with Visual Studio 2005 by Julia Lerman. She does an outstanding job of getting you started. Another good starting point is the MSDN Visualizer Architecture article. Also, there many articles here on CodeProject and the Internet covering visualizers.
There are four partners, running in two processes that are working together in the visualizer world.
Debugger Side
- Visual Studio Debugger - provides UI to select a visualizer to open.
- Visualizer UI - runs within the VS debugger process.
Debuggee Side
- Your program - the program you are debugging. This process has the visual tree we want to visualize.
- Visualizer Data Object - runs within your program's process.
Visual Studio plays the middle man handling communications between the two processes. The bottom line is, your visualizer UI has no data, until it makes a request to the visualizer data object. All data which moves between the two processes must be serialized. This is important to remember when building your data structures.
Both sides of the conversation are active throughout the visualizer's life. This allows your UI to make requests to the data object whenever it needs more data to display. The communications plumbing Microsoft provided is incredibly fast, even with all the serialization and deserialization going on.
Visualizer Project
If you are used to writing executables, this is going to blow your mind. Your visualizer complies into one class library .dll, part of which runs in one process and the other part is running in the other process. The classes from the Debugger process communicate through Visual Studio to classes in the Debuggee process.
How Does Mole's Project Fit Into This?
Visual Studio is only concerned about two classes in your visualizer: the debugger and debuggee.
First, your debugger-side class which derives from DialogDebuggerVisualizer
. In Mole, this is the Mole.Burrow
class.
Second, your debuggee-side class which derives from VisualizerObjectSource
. In Mole, this is the Mole.MoleVisualizerObjectSource
class.
Visual Studio identifies these classes by looking at the following attribute you have placed on the assembly in which your visualizer lives. Since all visualizers must be in certain directories, it is very easy for Visual Studio to locate all visualizers on your system.
<Assembly: System.Diagnostics.DebuggerVisualizer(GetType(Mole.Burrow), _
GetType(Mole.MoleVisualizerObjectSource), _
Target:=GetType(System.Windows.DependencyObject), _
Description:="Mole WPF Visualizer (Burrow back into your visual tree.)")>
The first attribute parameter is the type of our visualizer (Mole.Burrow
).
Second is the type of our data source (Mole.MoleVusualizerObjectSource
).
The third tells Visual Studio what type our visualizer wants to visualize. (In Mole speak, that is "what type Mole wants to Burrow into and molenate".) In our case, Mole can visualize DependencyObject
s, or any class which descends from DependencyObject
.
The fourth attribute parameter is the description Visual Studio displays in the listing of available visualizers when you are debugging. Glance back to the first image in this article, and you'll see the above description.
Mole.Burrow - Debugger Side - UI Side
Imports Microsoft.VisualStudio.DebuggerVisualizers
Public Class Burrow
Inherits DialogDebuggerVisualizer
Protected Overrides Sub Show(ByVal windowService As _
IDialogVisualizerService, _
ByVal objectProvider As IVisualizerObjectProvider)
Using frm As New frmMole(objectProvider)
frm.StartPosition = Windows.Forms.FormStartPosition.CenterScreen
windowService.ShowDialog(frm)
End Using
End Sub
End Class
Here is how the communication really works. Notice the second parameter, objectProvider
. objectProvider
is the object the debugger side will use when communicating with the data object. Just make your API calls using objectProvider
. Read about the IVisualizerObjectProvider Interface here.
In most visualizer examples on the web, you'll see calls being made to the Data Object in this class, with the results being passed to a form or message box. Mole needs to constantly communicate with the debuggee-side data object, so we just passed objectProvider
to the form and allow the form to take over the responsibility of data communication.
So you can see, Visual Studio does not open your form, you do. Visual Studio only makes a method call to Sub Show
. The rest is up to you.
Mole.MoleVisualizerObjectSource - Debuggee Side - Data Object Side
Code abbreviated here for clarity.
Public Class MoleVisualizerObjectSource
Inherits VisualizerObjectSource
Public Overrides Sub GetData(ByVal target As Object, _
ByVal outgoingData As System.IO.Stream)
MoleVisualizerObjectSource.Serialize(outgoingData, BuildTree(target))
End Sub
End Class
When your visualizer UI first opens, it requests data by calling the GetObject
method on objectProvider
. This, in turn, calls the GetData
method seen above.
Your Visualizer Object Source class is passed a reference to the object that was selected in the Visual Studio debugger. This class is working with and has full access to the selected object. This allows Mole to access the visual tree of the application being debugged.
One more item I need to make perfectly clear. Visual Studio only creates one instance of your Visualizer Object Source and makes its calls to this same object. This allows you to have module level objects that will survive between your calls to the Visualizer Object Source. Mole takes full advantage of this, as you will see in a moment.
MoleVisualizerObjectSource.Serialize
is a Shared
helper function that wraps the BinaryFormatter.Serialize
method. This method, along with the BinaryFormatter.Deserialize
method, is used by both the debuggee and the debugger sides.
The BuildTree
function does all the work building the outgoing data structure that represents your visual tree.
Mole Visualizer Form - Debugger Side - UI Side - Requesting Data
Private Sub LoadItemsOnUIThread()
_objTree = CType(_objectProvider.GetObject(), Tree)
CompleteLoading()
End Sub
Private Sub BackgroundWorker1_DoWork( _
ByVal sender As System.Object, _
ByVal e As System.ComponentModel.DoWorkEventArgs) _
Handles BackgroundWorker1.DoWork
Dim worker As System.ComponentModel.BackgroundWorker = _
CType(sender, System.ComponentModel.BackgroundWorker)
e.Result = _objectProvider.GetObject()
End Sub
Private Sub BackgroundWorker1_RunWorkerCompleted( _
ByVal sender As Object, _
ByVal e As System.ComponentModel.RunWorkerCompletedEventArgs) _
Handles BackgroundWorker1.RunWorkerCompleted
If e.Error IsNot Nothing Then
MessageBox.Show("Bummer. Exception while loading data." & _
vbCrLf & vbCrLf & e.Error.ToString, "Problems...", _
MessageBoxButtons.OK, MessageBoxIcon.Stop)
Me.Close()
Exit Sub
End If
_objTree = CType(e.Result, Tree)
CompleteLoading()
End Sub
Now things can get a little confusing. You'll notice that the above code fragments both make the same call to _objectProvider.GetObject()
. In the lifetime of the visualizer, only one of these methods will get called. Which one depends on how you are using the visualizer.
If you are just simply using the visualizer, the background worker code will be called.
Please read this note: If you want to debug Mole (meaning you want to step through Mole's code while it's visualizing an object), you can't spawn background worker threads because Visual Studio will throw an exception. Because of this limitation and the fact that I wanted to be able to debug Mole, I had to provide two ways, sync and async for Mole, to get its data from the Data Object.
Synchronous Data Object Call
The LoadItemsOnUIThread
sub calls _objectProvider.GetObject
on the form's UI thread and gets the data. Again, this type of call is required when debugging a visualizer.
Asynchronous Data Object Call
The .NET Framework provides a rich set of multithreading tools for developers. The BackgroundWorker
object simplifies multithreading by exposing a very simple interface to developers that encapsulates the complexities of multithreading. Visual Studio allows you to drop a BackgroundWorker
right on to your form, you could also create the BackgroundWorker
in code. So how you code your multithreading is up to you.
The call to _objectProvider.GetObject
is made asynchronously. When it completes, the BackgroundWorker1.RunWorkerCompleted
sub casts the data.
The CompleteLoading
sub processes the populated _objTree
object, filling the Element Tree and Element Properties grid.
How to Debug a Visualizer
Public Class MoleVisualizerObjectSource
Inherits VisualizerObjectSource
Public Overrides Sub GetData(ByVal target As Object, _
ByVal outgoingData As System.IO.Stream)
MoleVisualizerObjectSource.Serialize(outgoingData, BuildTree(target))
End Sub
Public Shared Sub TestMoleVisualizer(ByVal obj As DependencyObject)
Dim vdh As VisualizerDevelopmentHost = _
New VisualizerDevelopmentHost(obj, GetType(Mole.Burrow), _
GetType(Mole.MoleVisualizerObjectSource))
vdh.ShowVisualizer()
End Sub
End Class
After looking at this architecture, you might be wondering, how am I going to debug my visualizer? Microsoft really did an outstanding job making this task simple by providing the VisualizerDevelopmentHost
object.
In your VisualizerObjectSource
derived class, add a Shared
method that takes the same type of object that your visualizer does. In Mole's case, it's DependencyObject
.
Take notice of the VisualizerDevelopmentHost
constructor. It looks very similar to the attribute I described before which decorates the class library.
Calling TestMoleVisualizer from Another Application
Mole.MoleVisualizerObjectSource.TestMoleVisualizer(Me.btnViewVisualTree)
To debug your visualizer, you'll need to do a few simple things. First, in the project which has the object you want to visualize, you must add a reference to Microsoft.VisualStudio.DebuggerVisualizers
.
Next, place the above line of code where you want the visualizer to start. This call replaces you putting a breakpoint in your code, right clicking on the object, and selecting the visualizer you want to use. The parameter needs to be the same type object your visualizer supports.
Next, set breakpoints on one or both sides of your visualizer, debugger and debuggee.
Now run the project, and when the breakpoints are reached, Visual Studio will break and allow you to debug your visualizer.
Mole Concepts
Data Classes
With all the new visualizer concepts introduced above, I wanted to simplify the design of Mole. Since Mole's data objects are used on both the debugger and debuggee sides, I decided early on to not attach code to the data objects. You'll find a similar pattern being used in WCF with respect to data contracts. All of the data processing logic is separate from the data itself, which makes the entire system easier to understand and maintain. It can be confusing when some methods on an object can only be called when running in the debugger or debuggee process.
The debuggee side creates data. The debugger side consumes the data.
Mole's three data classes are in the Tree.vb, TreeElement.vb, and TreeElementProperty.vb files.
Tree Class
The Tree
class is used to contain the entire visual tree you are visualizing. When the class is first created, most of the data about individual elements in the tree is not loaded. This radically speeds up returning the visual tree from the data source. The lazy loading feature of Mole will load those unpopulated objects when the user requests to view them for the first time.
One bridge we had to cross was how to get the additional information that the debugger side object needed when the user wants to inspect an element in the tree. We use a generic Dictionary
on the debuggee side to hold a reference to every object in the visual tree and use a unique integer as the key. That key is assigned to the Id
property in the TreeElement
class. The code fragment below shows how the dependency object reference is saved in the Dictionary
. When the debugger side needs to request information from the debuggee side, it passes the key along with the request.
Private Function BuildElement(ByVal root As DependencyObject, _
ByVal objFirstVisual As DependencyObject, _
ByRef intInitialElementId As Integer) As TreeElement
_intElementIdCounter += 1
_dictVisualTree.Add(_intElementIdCounter, root)
...
...
End Function
TreeElement Class
The TreeElement
class holds data displayed in the Element Tree treeview control on the left side of the UI. This object tracks the state of lazy loaded objects' XAML, Image, and Properties.
TreeElementProperty Class
The TreeElementProperty
class holds the data which is loaded into the Element Property DataGridView
control. This data is lazy loaded. If you want to extend Mole to display more information in the DataGridView
, this is the class to modify.
Element Tree TreeView Control
The TreeView
control is, metaphorically speaking, the 175lbs brick slowing Mole down. It is the loading of the TreeView
nodes that takes most of the time, especially if you have thousands of visual tree elements. Special thanks to Josh for his code to lazy load the TreeView
's nodes. His version was better than mine, so Mole uses his.
Not only are the properties, images, and XAML lazy loaded, but the TreeView
control nodes are lazy loaded. This is what gives Mole the performance it requires.
Cast Reduction
Another performance enhancement came from making a custom MoleTreeNode
class that derives from TreeNode
. This class exposes a TreeElement
property to store a reference to the above TreeElement
class that is associated with a node in the Element Tree treeview. Using the TreeNode.Tag
property is a viable alternative to subclassing TreeNode
, but then you have to cast the Tag
property object every time you want to access the data.
Drilling Back for Collection Data
One of Mole's cool features is its ability to execute an on the fly drill through operation to retrieve a property's values that are stored in a collection. I'll show the code for this feature here.
Private Function GetColumns(ByVal obj As Object) As List(Of String)
Dim objList As New List(Of String)
For Each mi As MemberInfo In obj.GetType.GetMembers( _
BindingFlags.Public Or BindingFlags.Instance)
If mi.MemberType = MemberTypes.Property Then
objList.Add(mi.Name)
End If
Next
objList.Sort()
Return objList
End Function
Private Function MakeDataTableFromIEnumerable(ByVal target As _
DependencyObject, ByVal strPropertyName As String) As DataTable
Dim prop As PropertyInfo = target.GetType.GetProperty(strPropertyName)
Dim obj As IEnumerable = CType(prop.GetValue(target, Nothing), _
IEnumerable)
Dim dt As New DataTable
Dim bolColumnsCreated As Boolean = False
Dim intX As Integer
dt.RemotingFormat = SerializationFormat.Binary
Try
For Each objItem As Object In obj
If Not bolColumnsCreated Then
bolColumnsCreated = True
For Each s As String In GetColumns(objItem)
dt.Columns.Add(s)
Next
End If
If dt.Columns.Count = 0 Then
Return dt
End If
intX += 1
Dim dr As DataRow = dt.NewRow
For Each c As DataColumn In dt.Columns
Dim propInfo As PropertyInfo = _
objItem.GetType.GetProperty(c.ColumnName)
If propInfo IsNot Nothing Then
Dim value As Object = _
propInfo.GetValue(objItem, Nothing)
If value IsNot Nothing Then
dr.Item(c.ColumnName) = value.ToString
Else
dr.Item(c.ColumnName) = "null"
End If
End If
Next
dt.Rows.Add(dr)
If intX > _
INTEGER_MAXIMUM_ROWS_RETURNED_BY_COLLECTION_DATA_TABLES Then
Exit For
End If
Next
Catch ex As Exception
Debug.WriteLine(ex.ToString)
End Try
dt.AcceptChanges()
Return dt
End Function
The above code is simple Reflection in action. The function will iterate though the target collection items. After reading the first item, iterate through the property names, and add a table column for each property. Now for every item in the collection, iterate through the column names and retrieve the property's value and add it to the DataTableRow
.
Finally, it returns the DataTable
for rendering in the UI. Note the DataTable
's RemotingFormat
property has been set to SerializationFormat.Binary
. This is a performance enhancement from .NET 2.0.
Mole's Home Page
For everything Mole, visit Mole's home page by clicking here.
Mole Speak (fun stuff)
- Molenator - (n) A creator of Mole
- Burrow - (v) To dig through the visual tree
- Molenate - (v) To use Mole
Sample questions you can ask fellow WPF developers:
- Are you Mole'n? Response: Oh yea, I'm Mole'n.
- Do you Molenate? Response: Doesn't everyone?
- Do you Burrow? Response: Every time I need to debug my WPF code.
So do you Molenate? :P
Close
We hope this article can help someone learn a little more about Visual Studio Visualizers for WPF. We also hope that Mole helps WPF developers across the world have an easier time debugging complex user interfaces.
History
- 26 November 2007 - Initial release.
- 26 November 2007 - Added a new feature to the XAML viewer. You can now view the XAML in compressed or expanded format (attributes on single line or each on their own line). Changed the datagrids to not display the row headers. Uploaded new builds.
- 27 November 2007 - Josh revised the article a bit, sanded a few rough edges, put some polish on, added a few sentences, and removed a little here and there.
- 27 November 2007 - Karl added link to Mole's home page.