Click here to Skip to main content
15,881,559 members
Articles / Multimedia / GDI+

100% Reflective Class Diagram Creation Tool

Rate me:
Please Sign up or sign in to vote.
4.98/5 (498 votes)
14 Jun 2011CPOL28 min read 1.8M   39.6K   1.2K  
100% Reflective Class Diagram Creation Tool
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Text;
using System.Windows.Forms;

namespace AutoDiagramer
{
    #region ucExpander CLASS
    /// <summary>
    /// This control is a control that is used to represent
    /// one section of the overall class drwing. It has a title
    /// bar and n-many rows (RowContent). Each row is rendering
    /// with an image and a string. The control may be collapsed
    /// or expanded. This single control may be used to draw the
    /// following sections on overall class
    /// Properties,Events,Fields,Constructors,Methods
    /// </summary>
    public partial class ucExpander : UserControl
    {
        #region Instance Fields
        //private fields
        private Font _rowFont;
        private List<string> _rowContent;
        private PossibleTypes _examiningType = PossibleTypes.Methods;
        private int _oldhieght = 0;
        private States _currentState = States.Expanded;
        public enum States { Collapsed, Expanded };
        private int _pictureSize = 16;
        private int _RowSpacerSize = 2;
        private int _EndSpacerSize = 40;
        //public fields
        public enum PossibleTypes { Properties,Events,Fields,Constructors,Methods };
        public delegate void PanelStateChangedEventHandler(object sender, ExpanderSizeEventArgs args );
        public event PanelStateChangedEventHandler PanelStateChanged;
        #endregion
        #region Ctor
        /// <summary>
        /// Constructs a new ucExpander using the parameters provided
        /// </summary>
        /// <param name="title">The title for this control</param>
        /// <param name="examiningType">The type this control is gooing to represent.
        /// Could be one of the following Properties,Events,Fields,Constructors,Methods.
        /// This allows the control to grab the correct image to diaply for each row
        /// in the RowContent</param>
        public ucExpander(string title,PossibleTypes examiningType)
        {

            InitializeComponent();
            //set to flickerless style
            SetStyle(ControlStyles.AllPaintingInWmPaint | ControlStyles.ResizeRedraw |
                    ControlStyles.DoubleBuffer | ControlStyles.UserPaint, true);
            lblTitle.Text = title;
            this._examiningType = examiningType;
            _rowFont = new Font("Microsoft Sans Serif", 8.25F);
            this.Refresh();
            Application.DoEvents();

        }
        #endregion
        #region Private Methods
        /// <summary>
        /// Calls the getMaxWidth() and getMaxHeight() methods
        /// and causes the control to redraw
        /// </summary>
        private void RegenerateControl()
        {
            this.Width = getMaxWidth();
            this.Height = getMaxHeight();
            this.Invalidate();
            Application.DoEvents();
        }

        /// <summary>
        /// Paint each row (thats an image and the text)
        /// for each row in the RowContent list
        /// </summary>
        /// <param name="e">the event args</param>
        protected override void OnPaint(PaintEventArgs e)
        {

            int X_Pos = 0;
            int Y_Pos = pnlTop.Height;

            base.OnPaint(e);
            Graphics g = e.Graphics;
            SolidBrush b_Black = new SolidBrush(Color.Black);
            Image img = getImage();

            //paint each row
            foreach (string s in _rowContent)
            {
                g.DrawImage(img, new Point(X_Pos, Y_Pos));
                g.DrawString(s, _rowFont, b_Black, 
                    new Point(X_Pos + (_pictureSize+(_RowSpacerSize*2)), Y_Pos+(_RowSpacerSize*3)));
                Y_Pos += img.Height + _RowSpacerSize; 
            }
        }

        /// <summary>
        /// returns the correct image for the type is being examining
        /// So if this controls is displaying methods, return a methods
        /// Image
        /// </summary>
        /// <returns>An image for the type is being examining
        /// So if this controls is displaying methods, return a methods
        /// Image</returns>
        private Image getImage()
        {
            Image img = null;
            //look at what type is being examining and return correct image
            switch (this._examiningType)
            {
                case PossibleTypes.Constructors:
                    img = global::AutoDiagramer.Resource1.Constructors16;
                    break;

                case PossibleTypes.Events:
                    img = global::AutoDiagramer.Resource1.Events16;
                    break;

                case PossibleTypes.Properties:
                    img = global::AutoDiagramer.Resource1.Prop16;
                    break;

                case PossibleTypes.Methods:
                    img = global::AutoDiagramer.Resource1.Method16;
                    break;

                case PossibleTypes.Fields:
                    img = global::AutoDiagramer.Resource1.Fields16;
                    break;
            }
            return img;
        }

        /// <summary>
        /// Measures all contenst to see how height this control needs to be
        /// to fit its contents
        /// </summary>
        /// <returns>An int which is the highest height this control needs to be
        /// to fit its contents</returns>
        private int getMaxHeight()
        {
            int MaxHeight = pnlTop.Height + 1;  
            Graphics g = this.CreateGraphics();

            //look at each row
            if (_rowContent != null)
            {
                //work out what the highest content is
                foreach (string s in _rowContent)
                {
                    //picture is larger than text so use that for height, 
                    //also add on _RowSpacerSize height
                    MaxHeight += _pictureSize + _RowSpacerSize;
                }
            }
            //store old height (for re-expansion)
            _oldhieght = MaxHeight + _RowSpacerSize;
            //return the MaxHeight
            return MaxHeight + _RowSpacerSize;
        }

        /// <summary>
        /// Measures all contenst to see how wide this control needs to be
        /// to fit its contents
        /// </summary>
        /// <returns>An int which is the widest width this control needs to be
        /// to fit its contents</returns>
        private int getMaxWidth()
        {
            int MaxWidth = 0;
            Graphics g = this.CreateGraphics();

            //get the width of the title banner
            MaxWidth = lblTitle.Location.X +
                        (int)((SizeF)g.MeasureString(lblTitle.Text, lblTitle.Font)).Width + _EndSpacerSize; 

            //test each rows width
            if (_rowContent!=null)
            {
                //look at each row
                foreach(string s in _rowContent) 
                {
                    //work out what the widest content is
                    int rowWidth = (int)((SizeF)g.MeasureString(s, _rowFont)).Width + 
                        (_pictureSize+(_RowSpacerSize*3));
                    if (rowWidth > MaxWidth)
                    {
                        MaxWidth = rowWidth;
                    }
                }
            }
            //return the MaxWidth
            return MaxWidth;
        }

        /// <summary>
        /// Raised when the panel state changes state (collaped/expanded)
        /// </summary>
        /// <param name="sender"><see cref="ucExpander">this</see></param>
        /// <param name="e">the event args</param>
        private void OnPanelStateChanged(object sender, ExpanderSizeEventArgs args)
        {
            // Check if there are any Subscribers
            if (PanelStateChanged != null)
            {
                // Call the Event
                PanelStateChanged(sender, args);
            }
        }

        /// <summary>
        /// Will either expand or collapse the control, and will
        /// store the current state. And will fire the
        /// OnPanelStateChanged() event
        /// </summary>
        /// <param name="sender">picState</param>
        /// <param name="e">the event args</param>
        private void picState_Click(object sender, EventArgs e)
        {

            if (_currentState == States.Expanded)
            {
                _currentState = States.Collapsed;
            }
            else if (_currentState == States.Collapsed)
            {
                _currentState = States.Expanded;
            }

            switch (_currentState)
            {
                case States.Expanded:
                    this.picState.Image = global::AutoDiagramer.Resource1.Collapse9;
                    this.Height = _oldhieght;
                    break;

                case States.Collapsed:
                    this.picState.Image = global::AutoDiagramer.Resource1.Expand9;
                    this.Height = pnlTop.Height;
                    break;
            }

            // If anyone has subscribed, notify them
            OnPanelStateChanged(this, new ExpanderSizeEventArgs(this));
        }
        #endregion
        #region Public Properties
        /// <summary>
        /// gets / sets a List of strings that provide the
        /// row content for this control. The set will call
        /// the RegenerateControl() method
        /// </summary>
        [Browsable(false)]
        public List<string> RowContent
        {
            get { return _rowContent; }
            set
            {
                if (value != null)
                {
                    _rowContent = value;
                    RegenerateControl();
                }
            }
        }

        /// <summary>
        /// gets the current state expanded / collapsed
        /// </summary> 
        [Browsable(false)]
        public States CurrentState
        {
            get  { return this._currentState; }
        }

        /// <summary>
        /// gets / sets the Font to use for the rows
        /// </summary>
        [Category("Appearance")]
        [Browsable(true)]
        public Font RowFont
        {
            get { return _rowFont; }
            set { _rowFont = value; }
        }

        /// <summary>
        /// gets / sets the Font to use for the title
        /// </summary>
        [Category("Appearance")]
        [Browsable(true)]        
        public string TitleBarText
        {
            get { return lblTitle.Text; }
            set { lblTitle.Text = value; }
        }

        /// <summary>
        /// gets / sets the Color to use for the title bar
        /// </summary>
        [Category("Appearance")]
        [DefaultValue(typeof(Color))]
        [Browsable(true)]        
        public Color TitleBarColor
        {
            get { return pnlTop.BackColor; }
            set { pnlTop.BackColor = value; }
        }

        /// <summary>
        /// gets / sets the Color to use for the title text
        /// </summary>
        [Category("Appearance")]
        [DefaultValue(typeof(Color))]
        [Browsable(true)]        
        public Color TitleBarTextColor
        {
            get { return lblTitle.ForeColor; }
            set { lblTitle.ForeColor = value; }
        }
        #endregion
    }
    #endregion
    #region ExpanderSizeEventArgs CLASS
    /// <summary>
    /// provides the events args for the <see cref="ucExpander">
    /// ucExpander </see>SizeChanged event
    /// </summary>
    public class ExpanderSizeEventArgs : System.EventArgs
    {
        #region Instance Fields
        //instance fields
        private ucExpander ucExp;
        #endregion
        #region Ctor
        /// <summary>
        /// Constructs a new ExpanderSizeEventArgs using the params provided
        /// </summary>
        /// <param name="ucd">A <see cref="ucExpander">ucExpander </see>
        /// ucExpander</param>object which raised the event
        public ExpanderSizeEventArgs(ucExpander ucExp)
        {
            this.ucExp = ucExp;
        }
        #endregion
        #region Public Properties
        /// <summary>
        /// gets the CurrentState collapsed / expanded
        /// </summary>
        public ucExpander.States CurrentState
        {
            get { return this.ucExp.CurrentState; }
        }
        #endregion
    }
    #endregion
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

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


Written By
Software Developer (Senior)
United Kingdom United Kingdom
I currently hold the following qualifications (amongst others, I also studied Music Technology and Electronics, for my sins)

- MSc (Passed with distinctions), in Information Technology for E-Commerce
- BSc Hons (1st class) in Computer Science & Artificial Intelligence

Both of these at Sussex University UK.

Award(s)

I am lucky enough to have won a few awards for Zany Crazy code articles over the years

  • Microsoft C# MVP 2016
  • Codeproject MVP 2016
  • Microsoft C# MVP 2015
  • Codeproject MVP 2015
  • Microsoft C# MVP 2014
  • Codeproject MVP 2014
  • Microsoft C# MVP 2013
  • Codeproject MVP 2013
  • Microsoft C# MVP 2012
  • Codeproject MVP 2012
  • Microsoft C# MVP 2011
  • Codeproject MVP 2011
  • Microsoft C# MVP 2010
  • Codeproject MVP 2010
  • Microsoft C# MVP 2009
  • Codeproject MVP 2009
  • Microsoft C# MVP 2008
  • Codeproject MVP 2008
  • And numerous codeproject awards which you can see over at my blog

Comments and Discussions