Mole for WPF - Multifunction Visual Studio Visualizer for WPF

A multifunction visualizer that allows inspection of the visual tree. For each element in the visual tree, the developer can view all properties, visual images, run-time XAML, and can drill through to property collections to view their values.

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

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

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.

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 TabControls 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 TreeNodes in the entire TreeView. The Collapse All button will collapse all TreeNodes in the entire TreeView. The Expand Down button will expand all TreeNodes that are children of the currently selected TreeNode. The Collapse Down button will collapse all TreeNodes that are children of the currently selected TreeNode.

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

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!

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.

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 DependencyObjects, 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
PublicClass Burrow
Inherits DialogDebuggerVisualizer
ProtectedOverridesSub Show(ByVal windowService As _
IDialogVisualizerService, _
ByVal objectProvider As IVisualizerObjectProvider)
'rather than following the normal pattern of calling GetData or
'GetObject at this point, we will defer these calls to frmMole
'by passing the objectProvider to the form
'Using frm AsNew frmMole(objectProvider)
frm.StartPosition = Windows.Forms.FormStartPosition.CenterScreen
windowService.ShowDialog(frm)
EndUsingEndSubEndClass

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.

PublicClass MoleVisualizerObjectSource
Inherits VisualizerObjectSource
'''<summary/>''' Returns an abstract view of the entire visual tree
''' of the application being debugged.
''' This sub is actually called by Visual Studio when the frmMole
'''makes the objectProvider.GetObject call to the IVisualizerObjectProvider
'''</summary/>PublicOverridesSub GetData(ByVal target AsObject, _
ByVal outgoingData As System.IO.Stream)
MoleVisualizerObjectSource.Serialize(outgoingData, BuildTree(target))
EndSubEndClass

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.

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.

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

'you must disable all multithreading inside the visualizer when using
'this method
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.

PrivateFunction BuildElement(ByVal root As DependencyObject, _
ByVal objFirstVisual As DependencyObject, _
ByRef intInitialElementId AsInteger) As TreeElement
'this is the value used to uniquely identify each element
'allows both sides debugger and debuggee to refer to the same
'object across process boundaries
_intElementIdCounter += 1'save dependency property for future calls to TransferData
_dictVisualTree.Add(_intElementIdCounter, root)
...
...
EndFunction

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.

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.

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.

I've been using the visualizer today and its really great. I have a couple of feature requests if you get the chance (and assuming you agree these are worthwhile ):

* It would be nice to be able to associate a Favorite with a base type. For example, I want to make a favorite for the ActualWidth so that its a favorite for any derived element with that property (its defined on FrameworkElement).

* It would be nice to see the LogicalTree. Barring that, or perhaps in addition, you could show the LogicalParent and TemplatedParent as links on the element properties tab or have options in a right click menu for items in the tree to be able to navigate to them.

* It would be nice to have forward/back buttons to navigate the history of the items you selected in the tree. Reflector does this and I find it very useful when navigating around the tree.

* This isn't trivial but it would be nice to be able to modify the value of a property in the Element Properties list.

* It would be nice to have the snoop like feature of being able to delve into the properties of an object. E.g. If you want to see the values of a Template set on an element. Currently if value of a property is a complex object, you can't see the values of that object.

BTW, this is minor but you get an exception dialog if you click on the Help or Coll headers.

1. Is no problem. I can set up global favorites and keep the typed favorites or would you rather like it to just be global.

If we implement this, then the checkbox at the bottom behavior will need to change, since it now shows you everything if the type does not have any assigned favorites. Or we could add a "Show Type & Global Only" would solve this problem.

2. I'll speak with Josh about this tonight. Don't see a problem though.

3. No problem

4. For simple values types this is easy. I'll have to remember to invalidate the Image cache after sending a property back so that the image can be rerendered. Maybe the changes posted are not immediately recomplied and available? This will be interesting to see how this works!

5. I've look at this and for many complex objects this is real simple, like looking into the DataContext, very cool suggestion. I'll play around with this and give it my best shot. I think moving the "Col" column next to the "Value" column will be benificial. Renaming it to (+) would be a good idea too, or put a little drill icon in the grid for drilling back. Promise not to play drill.wav or dig.wav otherwise Josh will kill me. This way, for each of the values the user can click at what they are drilling or digging (Mole) into. Great suggestion.

6. I'm an idiot for missing this. When I added the "Col" column I must have missed visiting the Header click code. That was done at 3:00am last Sunday morning. 18 hours straight face down coding, like the good old days!

1. Is no problem. I can set up global favorites and keep the typed favorites or would you rather like it to just be global.

If we implement this, then the checkbox at the bottom behavior will need to change, since it now shows you everything if the type does not have any assigned favorites. Or we could add a "Show Type & Global Only" would solve this problem.

I think that just having a "global" list of property names is not only sufficient, but better. If a property name is in the list but the selected element does not have such a property, we just ignore it. That will be much more simple, and enables the feature request Drew made. If we do that, we can change the Favorites tab so that it provides a list of all the current favorite property names, and a way to add/remove property names. What do you say?

:josh:My WPF Blog[^]Without a strive for perfection I would be terribly bored.

We could easily allow the removal but adding? (Well, we could always reflect the .NET Framework and currently running solution to get all the possible property names on 4 - 5 threads and build a list that would be pretty long, just kidding.)

Mole is SCREAMING FAST. Visibly faster than the current release with the serialization and other optimizations you suggested. I have sub second load times with average WPF applications on my system. I learned a lot from your pointers!

That's interesting I wonder why that would matter. I could understand that if you changed something visual (e.g. Width) that it would not update the rendering of the element because of the retained graphics nature of WPF but that might be addressable by calling UpdateLayout on the element from within the ReplaceData callback. Could you explain a little more about the behavior you saw when you changed the value in lets say the ReplaceData callback? I did a quick and dirty test of doing a setvalue on the element within the replacedata callback and getvalue returned that value. It also seemed to retain that value after the visualizer was closed. Note, I tested in VS 2005 - not sure if there is different behavior in VS 2008.

Yes I was able to get it to work with elements other than the initial element. It was a crude test but basically in the current replacedata callback, I was getting the dependencyobject for the element being requested and then just using SetValue to change a value on the object - in my test I was just setting the WidthProperty to the current ActualWidth + 100. I let it then continue with code that was in there before that would populate the element (getting the image and props). The Width change took - I could see it if I did a getvalue - but the actualwidth wasn't changed because a layout pass hadn't been done. So I forced an update using the UpdateLayout call. I even went so far as to change the code that would only have populated the element once and let it do it each time the element was selected just so I could ensure it would adjust the values multiple times.

Hey guys. Nice work on the visualizer. I have a few comments/suggestions.

1) It seems that VisualSnapshot should be a static class with a single static method instead of a creatable class since it has no member variables and its only usage is to create an instance of it and use a method.

2) It might be good if you could remove the need for unsafe code in the VisualSnapshot. Perhaps instead of using fixed, you could just pin the array.
e.g.
GCHandle handle = GCHandle.Alloc(bits, GCHandleType.Pinned);

3) Since there can only be 1 initial element and since the tree seems to know the id of that element (InitialElementId), why does there have to be a property on the element for it? It would seem better to remove it since it would be false for every element but one.

4) Currently, you're using reflection to get the element name but since Name is defined on FrameworkElement (and add owner'd on FrameworkContentElement), you could just do something like:
strObjectName = root.GetValue(FrameworkElement.NameProperty);
Or if you want to handle other name type properties then do this in an if for framework(content)element and then do what you were doing.

5) IEnumerable derives from IEnumerable so instead of doing string checks and iterating the interfaces it implements, you could just check for the property type being assignable from this type.
e.g.
If GetType(IEnumerable).IsAssignableFrom(objPropertyDescriptor.PropertyType) Then

If the property type is object then you may want to get the value anyway and check to see if the value is ienumerable.

6) For the members of collections, it would be better to use TypeDescriptor.GetProperties rather than using reflection. It will pick up any inherited or attached properties. Also, as an optimization where you are just trying to see if the object has properties it might be better to just write a separate helper method rather then building a list of the properties just to check if the count is > 0. Doesn't seem necessary to allocate/populate a collection just to check its count.

7) You could probably improve the serialization/deserialization performance by implementing ISerializable on your serializable classes and manage writing out the data rather than relying upon the default reflection mechanism.

8) You could probably make it easier to debug the visualizer by using an #if check to conditionally use the LoadItemsOnUIThread or the background worker. This would prevent someone from having to comment/uncomment the code to debug it.
e.g.
#If DEBUG Then
LoadItemsOnUIThread()
#Else
Me.BackgroundWorker1.RunWorkerAsync()
#End If

Hope you don't mind the constructive criticism and thanks for the great tool.

Josh has sent me his list also and I will hop on each of your optimizations.

I can't wait to try your code for creating bitmaps. You should post an article just on that!!

#3 The reason for the propety that will only be True once is so that they TreeElement can be painted different. Your point is well taken and I'll remove it and just change the constructor to TreeElement.

#6 part b. This was a real pain, trying to figure out if a property was a collection and then trying to figure out if that collection had at least one item in it. I couldn't figure out any other way that enumerating the collection and after the first one, bail out. Most collections do have a Count property, except collections that only implemnet IEnumerable. I'll look into this deepter to see if there ia a better way.

#8 I had tried this but then ran into issues because of they way I was running Mole. You are correct, this is the method Mole should use.

Thank you for taking the time to participate in the process! I really appreciate learning better programming techniques.

Glad my comments could help. WRT #6b, the part I was commenting on was the "If GetColumns(objItem).Count > 0" call. You could just write a routine that gets the properties for the object but not create a list and just return true as soon as you find one. This is just to avoid creating a List of the property names when the list itself really isn't being used.

Here is your code in action! I also found another problem with the previous code when I moved it all into VB.NET. The stride must be a multiple of 4. In the past Mole and Woodstock were not checking for this. For some reason the C# version was working without this. So I added in the required padding if the stride was not a multiple of 4.

is that the whole point of having xaml is a separation of a code and a UI. This visualiser works only with UI controls which are referenced in the code. sorry but in a way it's a bad practice.

Thanks for the feedback. However, I completely disagree with you.

First of all, there is no "whole point" of XAML. It exists for many reasons. XML is tool-friendly, much more so than code. XML can easily be passed through firewalls, thus enabling dynamic UIs from Web services, etc. XML can easily be edited by hand. XML is a well understood serialization format, so the barrier to entry is low for most devs. Also...it promotes the separation of layout from code, but that's certainly not the reason why XAML exists.

Second, I don't know where you read that this visualizer only works with with controls referenced in code. That's just not true. Sure, some variable in your system has to reference an element in the visual tree, but that might just be a property of an event argument. This whole idea that WPF developers shouldn't WRITE CODE which interacts with WPF controls is ridiculous and obviously wrong.

Third, how can a debugger visualizer be a "bad practice"? What exactly is the "practice" here?

:josh:My WPF Blog[^]Without a strive for perfection I would be terribly bored.

I never said that WPF developers shouldn't WRITE CODE. Developers SHOULD write the code and DESIGNERS should bind the code to the UI. Some people can do both. the truly separated code can be extended with UI and UI can be changed or replaced without changing the code. And there is a very small need to edit xaml by hand(maybe in some rare cases where tool's support is still limited), in my opinion it's better not to.
About the practice - it's a bad practice to encourage people to reference UI in the business layer even throw event handlers. It's better to use commands instead of events.

I see what you mean, but in my experience any "real" (read: complicated) WPF application requires code to be written which interacts with elements in the visual tree.

Also keep in mind that not all WPF development is just about attaching a UI to business objects. There are people who never write line-of-business apps in WPF; but instead perhaps write controls, custom designers, etc. The more WPF-centric your development efforts become, the more useful it is to really know what's going on in your visual tree. That's where a tool like Mole becomes invaluable.

:josh:My WPF Blog[^]Without a strive for perfection I would be terribly bored.

By Microsoft's awesome design, all visualizers target a specific type of object.

This visualizer happens to target dependency objects.

Also, this visuzlizer works with XAML only projects no problem. All visualizers must be opened from within Visual Studio while debugging at a breakpoint. So, you must have at least one line of code to place a break point on. After breaking, simply open the visualizer over "this" c# or "me" vb.net in the code and your XAML only program's visual tree will be displayed in Mole.

In this example, the project only has loaded event code with one line of code that references the Window.Title property. Place your break point there.

You sir are to kind! Woodstock has some of the best programming I've seen in awhile. It should be a case study on the power of recursion in computer programming. I learned so much from working on the project and studying Woodstock.

Wow, great work, both of you! I read both of your blogs, and I'm really impressed with what you guys managed to come up with in a pretty short time. I have but one question... what's with that horrible color scheme? Don't you work for Infragistics? I hope they don't let you design their visual styles .

No worries about the colors--they really don't bother me at all. I just felt they were unusual enough that a joke was necessary . I do a lot of WPF development, so I'm really looking forward to an enhanced debugging experience with Mole (Woodstock was great too!).

One of the things I tried when developing Mole was to use WPF instead of WinForms. It will work. The only problem is the loading time. Even on my screaming machine at home with 4 CPU's and 4GB memory, it still took 4-5 seconds for a visualizer to open up that was WPF instead of WinForms.

I have not tried this on Orcas yet be will later this week. If Orcas can get a WPF form to open up FAST, then Mole can be pushed into WPF.