CHAPTER 3
A WPF application is made of many building blocks, including the user interface, view models, and data, just to mention a few. For each, you might have methods, variables, expressions, and even multithreaded code. For this reason, debugging a WPF application can be difficult outside of an appropriate environment. Fortunately, Visual Studio provides you with many integrated tool windows that simplify debugging and cover a huge number of scenarios. This chapter will provide guidance about the most commonly used debugging windows you will need with a WPF application, and it will offer information about writing better code.
The Locals window is a useful debugging window because it allows you to show the active local variables and their values. If the local variable represents a composite type, such as a class, you will be also able to see the type’s property and field values. In order to see it in action, consider the sample application created in Chapter 1 and place a breakpoint on the following line, inside the OpenButton_Click event handler:
this.ContentBox.Text = fileContent;
Run the application, browse for a file name, then click Open. When the breakpoint is hit and Visual Studio enters the break mode, select the Locals window, which should be enabled by default. If not, select Debug, Windows, Locals. As you can see in Figure 14, the Locals window shows a list of active local variables. For each variable, it shows the value and the type.

Figure 14: Investigating Local Variables with the Locals Window
If the variable type is a primitive type, such as a string, the Value column immediately shows the variable’s value, as for the fileContent local variable, of type string. If the variable type is a composite type, such as the e variable of type System.Windows.RoutedEventArgs, you can expand the variable and see its members. For each member, you will be able to see the type and current value; again, you can expand the member if it is a composite type—for example, expanding the e variable will cause the Locals window to show all the properties and fields (with values) exposed by the System.Windows.RoutedEventArgs type. The Locals window can be a real lifesaver when you need to check if a variable stores an expected (or unexpected) value.
You can also investigate variables with the Autos window, which shows the variables in three forms: used by the current statement, used by the previous three statements, and used by following three statements. You can also change a variable’s value with a simple double-click. In Figure 15, you can see how a variable is presented in red if it is related to a current breakpoint.

Figure 15: Investigating Variables with the Autos Window
The Call Stack window shows how method calls run in the stack, and it is useful for understanding the method call hierarchy.
Tip: If Just My Code is enabled, the Call Stack window shows a limited set of information. For a better understanding of Call Stack, disable Just My Code. You can then decide to re-enable it after reading about Call Stack.
Call Stack goes live when you debug your code—for example, when you press F11. Figure 16 shows the window in action.

Figure 16: Investigating Method Calls with Call Stack
Call Stack shows:
If the source code for a given method is not available, you can still view the assembly code by right-clicking a method name, then selecting Go to Disassembly. Figure 17 shows an example.

Figure 17: Disassembling a Method Call
Notice how the Disassembly window shows not only the disassembled method call, but also the address in memory of each instruction. You can also customize the appearance of Call Stack by right-clicking a column header and selecting the available options from the context menu, such as (but not limited to) parameter values and hexadecimal display. Call Stack is particularly useful when you get into an issue that is not apparently caused by the current piece of code and that needs further investigation through the entire stack of method calls.
You can track a variable by monitoring an object or expression using the Watch and Quick Watch windows. The difference is that Watch can monitor multiple variables, whereas Quick Watch can monitor one variable per time. There are four Watch windows available, which means you can monitor a large number of variables. In order to understand how they work, let’s make a slight modification to the OpenButton_Click event handler in the sample application, as shown in Code Listing 3.
Code Listing 3
private void OpenButton_Click(object sender, RoutedEventArgs e) { // Adding a variable to check if the string is not null. bool stringCheck = string.IsNullOrEmpty(this.FileNameBox.Text); if (!stringCheck) { string fileContent= OpenFile(this.FileNameBox.Text); this.ContentBox.Text = fileContent; } } |
Our goal is to monitor the behavior of the stringCheck variable, which we do in break mode. Next, press F11 to start the application instead of F5. Then we locate the stringCheck variable, right-click, and select Add Watch. At this point, the Watch 1 window will show the variable and display a message saying it does not exist in the current context, which is to be expected because the debugger has not yet been entered into the event handler.
Tip: Generally speaking, selecting Add Watch will open the first Watch window available among the four VS offers.
If you step into the code and enter into the OpenButton_Click handler, the Watch window will show the current evaluation for the expression assigned to the variable, which is False, as you can see in Figure 18.

Figure 18: Monitoring an Expression with the Watch Window
As you continue stepping through the code, you’ll see how the Watch window will show the result of the evaluation of the expression assigned to the stringCheck variable, which might or might not be true. The Quick Watch window works similarly, but it works on a single variable and is offered through a modal dialog.
Visual Studio 2015 has introduced an important feature that allows for debugging lambda expressions and LINQ queries inside the Watch window. In order to understand how to leverage this new tool, let’s make a couple modifications to the sample project. First, we’ll add a new button to the user interface as follows:
<Button Width="100" Height="30" Content="Feeling lucky"
x:Name="FeelingLuckyButton" Click="FeelingLuckyButton_Click"/>
This new button’s purpose is to launch a method that will open the first .txt document inside a given folder, then add the event handler and method shown in Code Listing 4.
Code Listing 4
private IEnumerable<string> EnumerateTextFiles(string directoryName) { // Using a lambda for demonstration purposes only. // You might want to use a search pattern instead. var list = Directory.EnumerateFiles(directoryName); var filteredList = list.Where(f => f.ToLower().Contains(".txt")); return filteredList; } private void FeelingLuckyButton_Click(object sender, RoutedEventArgs e) { this.FileNameBox.Text = OpenFile(EnumerateTextFiles("C:\\temp").FirstOrDefault()); } |
The EnumerateTextFiles method is using a lambda expression to filter the list of files in the specified folder. In your real code, you might prefer specifying the search pattern parameter for the Directory.EnumerateFiles method, but using a lambda is necessary in order to demonstrate how to use the new debugging features. At this point, place a breakpoint on the EnumerateTextFiles method, then start debugging. When the debugger enters this method, right-click the filteredList variable, then select Add Watch. When you press F11 over this variable, the Watch window will evaluate the expression, which includes expanding the Results View element that shows the result of the lambda. Figure 19 demonstrates this.

Figure 19: Debugging a Lambda Expression
In this way, you can investigate the expression result and see if it is working as expected.
More often than not, a .NET application can run multiple threads. Sometimes multiple threads are run in order to suit how the system manages an application or because we have programmatically created new threads for delegating tasks to separate units of execution. Visual Studio offers the Threads window (Ctrl+Alt+H), in which you can see the list of running threads (see Figure 20).

Figure 20: Watching the List of Running Threads
For each thread, you can see the name, the ID, the category, and the location. With the category, you can see how the main thread corresponds to the user interface thread in the application. This is demonstrated in the Location column, where you not only find the name of the module, but also the method that is currently being executed. In the case of threads created programmatically, they will be listed in the window and you will be able to get information about them. The most interesting feature of the Threads window is that you can also select a thread, then click Search Call Stack. This action will open the Call Stack window, thereby showing the method calls in the specified thread.
Visual Studio offers the Tasks window, a convenient way of investigating tasks that the runtime creates when you code asynchronous methods using the Async/Await pattern. In order to understand how this works, let’s add a new asynchronous method to the sample application that opens a text file based on the Async/Await pattern. This is shown in Code Listing 5.
Code Listing 5
private async Task<string> OpenFileAsync(string fileName) { string result = null; using (var fs = new FileStream(fileName, FileMode.Open)) { using (var reader = new StreamReader(fs)) { result = await reader.ReadToEndAsync(); } } return result; } |
In order to use this method, you will need to mark the OpenButton_Click event handler with the async modifier, and you will need to change the assignment of the fileContent variable as follows:
string fileContent = await OpenFileAsync(this.FileNameBox.Text);
If you place a breakpoint on the OpenFileAsync method and enable the Tasks window (Ctrl+Shift+D, K) while in break mode, you will see the status of a task, its time of execution, and its location (see Figure 21).

Figure 21: Monitoring Asynchronous Tasks
Note: The Tasks window can also be used with parallel programming based on the Task Parallel Library (TPL) for investigating the execution of parallel tasks.
The more complex the WPF application, the more you will need sophisticated debugging tools. Visual Studio offers everything you need in order to perform complex debugging over your apps. In fact, the IDE provides many debugging windows that you can use to inspect variables (Locals and Autos windows), evaluate expressions (Watch windows), investigate method calls (Call Stack window), and analyze threads and tasks (Threads and Tasks windows). All of these windows are nonmodal, they work docked inside the IDE and, therefore, you can always keep an eye on your code, which means you can be more productive.