Search icon CANCEL
Arrow left icon
Explore Products
Best Sellers
New Releases
Books
Videos
Audiobooks
Learning Hub
Conferences
Free Learning
Arrow right icon
Arrow up icon
GO TO TOP
Mastering Windows Presentation Foundation

You're reading from   Mastering Windows Presentation Foundation Build responsive UIs for desktop applications with WPF

Arrow left icon
Product type Paperback
Published in Mar 2020
Publisher Packt
ISBN-13 9781838643416
Length 626 pages
Edition 2nd Edition
Languages
Arrow right icon
Author (1):
Arrow left icon
Sheridan Yuen Sheridan Yuen
Author Profile Icon Sheridan Yuen
Sheridan Yuen
Arrow right icon
View More author details
Toc

Table of Contents (15) Chapters Close

Preface 1. A Smarter Way of Working with WPF 2. Debugging WPF Applications FREE CHAPTER 3. Writing Custom Application Frameworks 4. Becoming Proficient with Data Binding 5. Using the Right Controls for the Job 6. Adapting the Built-In Controls 7. Mastering Practical Animations 8. Creating Visually Appealing User Interfaces 9. Implementing Responsive Data Validation 10. Completing that Great User Experience 11. Improving Application Performance 12. Deploying Your Masterpiece Application 13. What Next? 14. Other Books You May Enjoy

Debugging data bound values

So far, we have seen that we can utilize a number of sources of information to help with tracking down the causes of our problems. However, what about actual debugging? In other GUI languages, we can add breakpoints at various locations in our code and watch our values changing as we step through our code. While we can also do this with WPF applications, it is not always so obvious where to put our breakpoints to ensure that program execution will hit them.

If you remember from the previous chapter, the CommandManager.RequerySuggested event is raised when the CommandManager class detects a change in the UI that could reflect on whether a command could execute or not. Well, it turns out that two of the conditions that the CommandManager looks out for is when the application window is either activated or deactivated and we can take advantage of this to help us when debugging. Note that the application window is deactivated when the user moves focus from it and is reactivated when the user returns focus to it.

Therefore, while running the application side by side with Visual Studio, we can put a breakpoint in any method that is being used as a canExecute handler for our ActionCommand class, thereby removing focus from the application. Now, when we click back on the WPF application, the focus will be returned to it.

This will cause the CommandManager.RequerySuggested event to be raised and as a result, the canExecute handler will be called and our breakpoint will be hit. This basically means that we are able to get the program execution into our View Models to debug parameter values any and every time that we need to. Let's see what else we can do to help fix our data binding errors.

Outputting values to UI controls

One of the simplest ways of working out what values our data bound properties have is to just data bind them to other UI controls that have a textual output. For example, if we have a collection of items and we want to do something with the selected item, but whatever that is isn't working, we need to verify that our binding to that selected item is correct.

To visualize the result of the binding, we can simply copy and paste the binding path to the Text property of a TextBox and run the application. If our binding path is correct, we'll see something output in the TextBox control and if not, we'll know that the problem that we're having is in fact, down to the binding path. We can therefore, use this method to verify that objects that don't normally have a textual output are at least correctly data bound or not.

This simple technique can help in any situation where the faulty data binding is not already rendered in a text-based UI control. For example, we might need to debug a data bound value because a particular visual effect that is created with a DataTrigger instance is not working and we need to determine whether the problem is related to the UI control or the data binding path.

Catching changing Dependency Property values

As we saw at the beginning of this chapter, the WPF Framework won't call the CLR property wrappers of our Dependency Properties when the property values are changing. However, there is a way to accomplish this using callback handlers. In fact, we've already seen an example of this when we were looking at the creation of the OnEnterKeyDown Attached Property. Let's remind ourselves what that looked like:

public static readonly DependencyProperty OnEnterKeyDownProperty =  
  DependencyProperty.RegisterAttached("OnEnterKeyDown", 
typeof(ICommand), typeof(TextBoxProperties),
new PropertyMetadata(OnOnEnterKeyDownChanged));

...
public static void OnOnEnterKeyDownChanged(
DependencyObject dependencyObject, DependencyPropertyChangedEventArgs e) { TextBox textBox = (TextBox)dependencyObject; if (e.OldValue == null && e.NewValue != null) textBox.PreviewKeyDown += TextBox_OnEnterKeyDown; else if (e.OldValue != null && e.NewValue == null) textBox.PreviewKeyDown -= TextBox_OnEnterKeyDown; }

For this Attached Property, we used a particular overload of the DependencyProperty.RegisterAttached method that accepts a PropertyMetadata object, which enabled us to assign a PropertyChangedCallback handler to the property. Note that there is an identical overload for the DependencyProperty.Register method for declaring Dependency Properties.

Program execution will enter these PropertyChangedCallback handlers each time their related Dependency Property changes and so, that makes them perfect for debugging their values. While we don't often need to attach these handlers, it only takes a moment to add one when we need to and they enable us to find out what's going on with the Dependency Property values at runtime.

Exploiting converters

If we're having a problem with a data binding that uses an IValueConverter to convert the data bound value from one type to another, then we can place a breakpoint into the Convert method of the converter. As long as we have correctly set up the converter, we can be sure that the breakpoint will be hit when the binding is evaluated at runtime. If it doesn't get hit, that will mean that we have not set it up correctly.

However, even when we are not already using a converter on a binding that is not displaying the value that we are expecting, we can still add one just for this purpose. We can either add an existing converter to the binding, if we have one of the relevant type, or we can create a simple converter specifically for the purpose of debugging and use that instead. Let's take a look at how we might do this:

[ValueConversion(typeof(object), typeof(object))] 
public class DebugConverter : IValueConverter 
{ 
  public object Convert(object value, Type targetType, object parameter,
CultureInfo culture) { if (Debugger.IsAttached) Debugger.Break(); return value; } public object ConvertBack(object value, Type targetType,
object parameter, CultureInfo culture) { if (Debugger.IsAttached) Debugger.Break(); return value; } }

As you can see from the preceding code snippet, it's a very simple implementation of the IValueConverter interface. We start by specifying that we are converting from object to object in the ValueConversion attribute, thereby outlining that we are not actually converting any data bound values in this converter. The rest of the class represents a typical converter class, but without any conversion code.

The only real point of interest here are the two calls to the Debugger.Break method from the System.Diagnostics assembly. When the program execution reaches either of these method calls, it will automatically break, just as if there were breakpoints set on these lines. Therefore, when using this converter, we don't even need to set a breakpoint; we can just plug it into the binding, run the program, and investigate the value of the value input parameter when the data bound value is changed.

It can be attached like any other converter:

xmlns:Converters="clr-namespace:CompanyName.ApplicationName.Converters; 
  assembly=CompanyName.ApplicationName.Converters" 
... 
<UserControl.Resources> 
  <Converters:DebugConverter x:Key="Debug" /> 
</UserControl.Resources> 
... 
<ListBox ItemsSource="{Binding Items, Converter={StaticResource Debug}}" />

However, this method can be unsafe to use in a production environment and the converter should be removed when debugging is finished. If it is left connected in release code, an exception will be thrown at runtime, complaining that Windows has encountered a user-defined breakpoint. Although I wouldn't recommend leaving a converter that is just used for debugging data bound values connected in a production environment, we can make a slight alteration to it to completely eliminate the danger of this occurring:

[ValueConversion(typeof(object), typeof(object))] 
public class DebugConverter : IValueConverter 
{ 
  public object Convert(object value, Type targetType, object parameter,
CultureInfo culture) { Break(value); return value; } public object ConvertBack(object value, Type targetType,
object parameter, CultureInfo culture) { Break(value); return value; }

[Conditional("DEBUG")]
private void Break(object value)
{
Debugger.Break();
}
}

Now, the Debugger.Break method and the data bound value have been moved into a separate Break method, where the value of the value input parameter can be inspected. Note the use of the ConditionalAttribute attribute on this new method. It provides a way to include or exclude methods that it has been set on, depending on the current solution configuration. If the configuration is set to debug, this method can be called, but otherwise, all calls to it are removed from the compiled code. In this way, we can be assured that we will not run into problems with our release code.

You have been reading a chapter from
Mastering Windows Presentation Foundation - Second Edition
Published in: Mar 2020
Publisher: Packt
ISBN-13: 9781838643416
Register for a free Packt account to unlock a world of extra content!
A free Packt account unlocks extra newsletters, articles, discounted offers, and much more. Start advancing your knowledge today.
Unlock this book and the full library FREE for 7 days
Get unlimited access to 7000+ expert-authored eBooks and videos courses covering every tech area you can think of
Renews at €18.99/month. Cancel anytime