ILearnable .Net

April 2, 2014

Display control hierarchy in winforms application

Filed under: Uncategorized — andreakn @ 13:08

I recently changed projects and suddenly found myself in a MASSIVE winforms application… Now normally I have no problem navigating massive codebases, after all all you have to do is to right click and select “inspect element” in chrome to see which part of the code created this part of the GUI, right? not so in winforms…

after spending a bit of time searching for strings found nearby what I wanted to track down in the codebase I hit me: “there’s got to be a better way!!”

Luckily for me all GUI controls in the solution inherits from a common baseclass, so I was able to tweak that baseclass so that whenever you press the F12 key you enter “inspection mode” which makes any control clicked display a messagebox with its control hierarchy path all the way up to the form.
the result looks somewhat like this: Control hieararchy for clicked control

 public class TheBaseControl : SomeOtherControlBase
   {
      private bool currentlyInInspectMode;
      protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
      {
         ActivateOrDeactivateMouseHack(keyData);
         return base.ProcessCmdKey(ref msg, keyData);
      }

      private void ActivateOrDeactivateMouseHack(Keys keyData)
      {
         if (keyData.HasFlag(Keys.F12) )
         {
            if (!currentlyInInspectMode)
            {
               SetInspectModeRecursively(this, true, true);
               currentlyInInspectMode = true;
            }
         }
         else
         {
            if (currentlyInInspectMode)
            {
               SetInspectModeRecursively(this, false, true);
               currentlyInInspectMode = false;
            }
         }
      }

      private void SetInspectModeRecursively(Control ctrl, bool active, bool initialEventSource)
      {
         if (ctrl is TheBaseControl &&!initialEventSource) return;
         if (ctrl == null) return;
         if (active)
            ctrl.MouseDown += DisplayControlInfo;
         else
            ctrl.MouseDown -= DisplayControlInfo;

         foreach (var control in ctrl.Controls)
         {
            SetInspectModeRecursively(control as Control, active, false);
         }
      }

      private void DisplayControlInfo(object sender, MouseEventArgs e)
      {
         var clickedControl = FindControlAtCursor( this.ParentForm);
         var controlpath = "";
         var tip = clickedControl;
         while (tip != null)
         {
            controlpath = string.Format("[{0}:id={1}]{2}{3}", tip.GetType().FullName, tip.Name, Environment.NewLine,
               controlpath);
            tip = tip.Parent;
         }
         MessageBox.Show("You just clicked on " + Environment.NewLine+controlpath);
      }
      
      public static Control FindControlAtPoint(Control container, Point pos)
      {
         Control child;
         foreach (Control c in container.Controls)
         {
            if (c.Visible && c.Bounds.Contains(pos))
            {
               child = FindControlAtPoint(c, new Point(pos.X - c.Left, pos.Y - c.Top));
               if (child == null) return c;
               else return child;
            }
         }
         return null;
      }

      public static Control FindControlAtCursor(Form form)
      {
         Point pos = Cursor.Position;
         if (form.Bounds.Contains(pos))
            return FindControlAtPoint(form, form.PointToClient(Cursor.Position));
         return null;
      }
   }

Blog at WordPress.com.