Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / programming / debugging

Customize the Debugging Windows : Change Debugging Window View as per your requirements

4.97/5 (11 votes)
27 Sep 2010CPOL4 min read 40.5K  
In this blog post I am going to explain how you can customize the complete view of the debugging window during debugging of application. By complete view means, where you can add own Properties, can customize the result, manipulate the data, hide properties which may not need during debugging etc. I

In this blog post I am going to explain how you can customize the complete view of the debugging window during debugging of application. By complete view means, where you can add own Properties, can customize the result, manipulate the data, hide properties which may not need during debugging etc. In one of my previous blog post, I have explained how we can customize the view of the debugging windows using DebuggerBrowseable and DebuggerDisplay attributes over Few Tips on Customizing Debugging Window View in Visual Studio . But, both these two attributes are limited to customize the view for a specific class and they can only show you the information for the particular class members . In this blog post you will see how we can create new view for some existing debugging view using “DebuggerTypeProxy” attributes. From the below snaps you can understand what kind of customization we can do inside a debugging window.

Overall


To start with this, first let’s see what is the default behavior of debugging window for the below block of code. I took one simple example of Student Data, where I have 3 classes “Student” , “Address” and “Marks” .

class Student
  {
      /// <summary>
      /// Gets or sets the roll.
      /// </summary>
      /// <value>The roll.</value>
      public int Roll { get; set; }

      /// <summary>
      /// Gets or sets the name.
      /// </summary>
      /// <value>The name.</value>
      public string Name { get; set; }

      /// <summary>
      /// Gets or sets the marks.
      /// </summary>
      /// <value>The marks.</value>
      public Marks Marks { get; set; }

      /// <summary>
      /// Gets or sets the addresses.
      /// </summary>
      /// <value>The addresses.</value>
      public Address Addresses { get; set; }
  }

  /// <summary>
  /// Address of Students
  /// </summary>

  class Address
  {
      /// <summary>
      /// Gets or sets the address1.
      /// </summary>
      /// <value>The address1.</value>

      public string City { get; set; }

      /// <summary>
      /// Gets or sets the address2.
      /// </summary>
      /// <value>The address2.</value>
      public int Pin { get; set; }
  }

  /// <summary>
  /// Marks of Student for different subjects
  /// </summary>
  public class Marks
  {
      /// <summary>
      /// Gets or sets the subject1.
      /// </summary>
      /// <value>The subject1.</value>
      public int Subject1 { get; set; }

      /// <summary>
      /// Gets or sets the subject2.
      /// </summary>
      /// <value>The subject2.</value>
      public int Subject2 { get; set; }

      /// <summary>
      /// Gets or sets the subject3.
      /// </summary>
      /// <value>The subject3.</value>
      public int Subject3 { get; set; }

  }

Where Student class having two properties of type Address and Marks classs. Now, below is your main methods where we are creating some dummy mock data for student. Our main objective is to view the Debug window.

static void Main(string[] args)
       {
           List<Student> student = new List<Student>();
           student.Add(new Student { Roll = 1, Name = "Abhijit", Marks= new Marks {Subject1=56,Subject2=66,Subject3=67} , Addresses = new Address { City = "add1", Pin = 312312 } });
           student.Add(new Student { Roll = 2, Name = "Abhishek", Marks = new Marks {Subject1=78,Subject2=66,Subject3=67}, Addresses = new Address { City = "add3", Pin = 123123 } });
           student.Add(new Student { Roll = 3, Name = "Rahul", Marks = new Marks {Subject1=78,Subject2=43,Subject3=77}, Addresses = new Address { City = "add5", Pin = 123123 } });
           student.Add(new Student { Roll = 4, Name = "Sunil", Marks = new Marks {Subject1=74,Subject2=96,Subject3=57}, Addresses = new Address { City = "add11", Pin = 57567 } });
           student.Add(new Student { Roll = 5, Name = "Atul", Marks = new Marks {Subject1=78,Subject2=76,Subject3=47}, Addresses = new Address { City = "add12", Pin = 57567 } });
           student.Add(new Student { Roll = 6, Name = "Kunal", Marks = new Marks {Subject1=56,Subject2=66,Subject3=67}, Addresses = new Address { City = "add12", Pin = 46456 } });
       }

Now, just put a breakpoint at the end of the main method and watch the debug data tip. It will look likes below,

Debugging2

Where you can see the all Address, Marks are in expanded mode. Even if you look at the Watch window, you have to expand each and every list of object to get the data.

Debugging1

Though this is a very simple class structure where you have only few set of data, but in real life there are many cases where you have to deal with complex objects. All of those object properties may not relevant for you to check or you may want to very simple view of your debugging window, where you can see the on demand data.

In this scenarios, You can use the “DebuggerTypeProxy” attributes along with “DebuggerBrowseable”. Let me first show you how this things works, then I will explain the details of the use. To create a customize debugging view, create a proxy class, by proxy it means, it will bypass the actual debugging windows and will the the proxy window for the class you defined the proxy.

So, create a internal class for the Student Proxy shown as below.

Debugging4

This call is going to the view for student class debug mode. So create all the custom properties over here. Skip those properties which you don’t want to see, change the properties names which is more meaning full during debugging, Add new properties which by which you can get some manipulated data. Below snaps showing few of them.

Debugging5

See, from the above image you can see I have used some existing properties such as “Roll”, “Name” and “City” . I have also made changes on properties name “Pin” to “PinNo” along with that I have added two new properties which is used to show all the marks of students in a single view and New properties rank to calculate the rank based on the marks.

Till now what I have discussed is all about the creating the proxy class, which is nothing but your new view for debugging window for the students objects.

Now, you have to assign this proxy class to let your existing class know that, debugger will use the proxy view during debugging.

Debugging6

You can see in the above image, I have assigned StudentDebuggerProxy Class as DebuggerTypeProxy attributes. You can also see, I have also specified “DebuggerDisplay” attributes to get the exact name of the student in debugging datatip.

That’s all. Again run the program with the same breakpoint position and check for the debugging view data tip.

Debugging7

Yes, this is exactly a new view of your debugging window. This view is showing only those data that are defined your proxy class. You can see all of your different classes data with out expanding. In a single properties you can see the value of different properties. You can also see the impact of using “DebuggerDisplay” attributes, as it’s showing like “Details information of “Student Name””. You can check the same in Quick watch window also,

Debugging8

Yes, quick watch windows is containing only those information that are defined on debugger proxy class. Here you can see all the data with in a single view without expanding. Below snaps showing the difference between two quick watch window.

Debugging9

I hope, I have explained well to understand to customizing the debugging windows view. Below is the complete code snippet for this sample application. You can run and test the steps that I have mentioned.

namespace DebugWindowCustomizationDemo
{
    class Program
    {
        static void Main(string[] args)
        {
            List<Student> student = new List<Student>();
            student.Add(new Student { Roll = 1, Name = "Abhijit", Marks= new Marks {Subject1=56,Subject2=66,Subject3=67} , Addresses = new Address { City = "add1", Pin = 312312 } });
            student.Add(new Student { Roll = 2, Name = "Abhishek", Marks = new Marks {Subject1=78,Subject2=66,Subject3=67}, Addresses = new Address { City = "add3", Pin = 123123 } });
            student.Add(new Student { Roll = 3, Name = "Rahul", Marks = new Marks {Subject1=78,Subject2=43,Subject3=77}, Addresses = new Address { City = "add5", Pin = 123123 } });
            student.Add(new Student { Roll = 4, Name = "Sunil", Marks = new Marks {Subject1=74,Subject2=96,Subject3=57}, Addresses = new Address { City = "add11", Pin = 57567 } });
            student.Add(new Student { Roll = 5, Name = "Atul", Marks = new Marks {Subject1=78,Subject2=76,Subject3=47}, Addresses = new Address { City = "add12", Pin = 57567 } });
            student.Add(new Student { Roll = 6, Name = "Kunal", Marks = new Marks {Subject1=56,Subject2=66,Subject3=67}, Addresses = new Address { City = "add12", Pin = 46456 } });
        }
    }

    /// <summary>
    /// Student Debugger Proxy Class
    /// </summary>
    ///
    internal class StudentDebuggerProxy
    {
        private Student student;
        /// <summary>
        /// Initializes a new instance of the <see cref="StudentDebuggerProxy"/> class.
        /// </summary>
        /// <param name="student">The student.</param>
        public StudentDebuggerProxy(Student student)
        {
            this.student = student;
        }

        /// <summary>
        /// Gets the roll.
        /// </summary>
        /// <value>The roll.</value>
        public int Roll
        {

            get
            {
                return this.student.Roll;
            }
        }

        /// <summary>
        /// Gets the name.
        /// </summary>
        /// <value>The name.</value>
        public string Name
        {
            get
            {
                return this.student.Name;
            }
        }

        /// <summary>
        /// Gets the city.
        /// </summary>
        /// <value>The city.</value>
        public string City
        {
            get
            {
                return this.student.Addresses.City;
            }
        }

        /// <summary>
        /// Gets the pin.
        /// </summary>
        /// <value>The pin.</value>
        public int PinNo
        {
            get
            {
                return this.student.Addresses.Pin;
            }
        }

        /// <summary>
        /// Gets the marks details.
        /// </summary>
        /// <value>The marks details.</value>
        public string MarksDetails
        {
            get
            {
                string marksDetails = string.Format("First Subject  - {0} Second Subject - {1} Third Subject - {2} | Total = {3} ", this.student.Marks.Subject1.ToString(), this.student.Marks.Subject2.ToString(), this.student.Marks.Subject3.ToString(), (this.student.Marks.Subject1 + this.student.Marks.Subject2 + this.student.Marks.Subject3).ToString());
            return marksDetails;
            }
        }

        /// <summary>
        /// Gets the rank.
        /// </summary>
        /// <value>The rank.</value>
        private string Rank
        {
            get
            {
               int total = this.student.Marks.Subject1 + this.student.Marks.Subject2 + this.student.Marks.Subject3;
               string grade;
               if (total > 200)
                   grade = "A";
               else if (total > 150)
                   grade = "B";
               else
                   grade = "C";
               return grade;

            }
        }
    }

  [DebuggerDisplay("Details Information of {Name}")]
  [DebuggerTypeProxy(typeof(StudentDebuggerProxy))]
    class Student
    {
        /// <summary>
        /// Gets or sets the roll.
        /// </summary>
        /// <value>The roll.</value>
        public int Roll { get; set; }

        /// <summary>
        /// Gets or sets the name.
        /// </summary>
        /// <value>The name.</value>
        public string Name { get; set; }

        /// <summary>
        /// Gets or sets the marks.
        /// </summary>
        /// <value>The marks.</value>
        public Marks Marks { get; set; }

        /// <summary>
        /// Gets or sets the addresses.
        /// </summary>
        /// <value>The addresses.</value>
        public Address Addresses { get; set; }
    }

    /// <summary>
    /// Address of Students
    /// </summary>

    class Address
    {
        /// <summary>
        /// Gets or sets the address1.
        /// </summary>
        /// <value>The address1.</value>

        public string City { get; set; }

        /// <summary>
        /// Gets or sets the address2.
        /// </summary>
        /// <value>The address2.</value>
        public int Pin { get; set; }
    }

    /// <summary>
    /// Marks of Student for different subjects
    /// </summary>
    public class Marks
    {
        /// <summary>
        /// Gets or sets the subject1.
        /// </summary>
        /// <value>The subject1.</value>
        public int Subject1 { get; set; }

        /// <summary>
        /// Gets or sets the subject2.
        /// </summary>
        /// <value>The subject2.</value>
        public int Subject2 { get; set; }

        /// <summary>
        /// Gets or sets the subject3.
        /// </summary>
        /// <value>The subject3.</value>
        public int Subject3 { get; set; }

    }

}

Summary : Use the DebuggerTypeProxy attribute attribute when you need to significantly change the debugging view of a type. You can customize the properties, add new properties, you can also manipulate the result to show. This can be used at the assembly level. No private members of the debugger proxy class won’t be visible to debugging window. Here is nice explanation of DebuggerTypeProxy.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)