Custom shapes to user-drawn controls-Collection of common programming errors


  • msdn

    I wish to create a custom control that extends all of the typical features of a panel, but in a different shape. Attached is a picture of what I want to make the panel look like. The blue edge should have the ability to change colors on the fly based on whatever color the user choses from a pallet. The bottom or top border of the control should be this blue edge. Is this possible? I know the panel shape doesn’t make a lot of sense, but it is needed for my project. Any help would be greatly appreciated. I have a general idea of the concept, so a link to a sample of a custom sided control would be great. Thanks in advance.

    Sample images of the panels I wish to make:

    Panel 1:

    Panel 2:


  • msdn1

    Hi mkruluts,

    It is surely possible to do that. Here is a checklist(we assume you are using WinForm rather than WPF):

    • write a class deriving from Panel;
    • add an EdgeColor property for your panel class;
    • override the OnPaintBackground method and do some drawing stuffs in it. This is the key step, but not difficult with the help of GDI+. Draw the edge part with the color specified by the EdgeColor property.

    If you are not familiar with GDI+, here is an article to get started: http://www.devsource.com/c/a/Languages/Getting-Started-with-GDI-in-C-Applications/


  • msdn2

    Hey thanks for your response Hillin. I just got to it this morning. Below is my code, please let me know if there is anything you would change on it to make it better:

    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data;
    using System.Drawing;
    using System.Linq;
    using System.Text;
    using System.Windows.Forms;
    namespace Controls
    {
        public partial class TopPanel : Panel
        {
            private Color _EdgeColor = Color.Transparent;
            public TopPanel()
            {
                InitializeComponent();
                this.BackColor = Color.Transparent;
                this.BackgroundImage = global::Controls.Properties.Resources.top;
                this.MaximumSize = new System.Drawing.Size(800, 67);
                this.MinimumSize = new System.Drawing.Size(800, 67);
                this.Size = new System.Drawing.Size(800, 67);
            }
            protected override void OnPaint(PaintEventArgs pe)
            {
                base.OnPaint(pe);
                Draw(pe.Graphics);
            }
            public void Draw(Graphics e)
            {
                e.DrawLine(new Pen(_EdgeColor, 5), 0, 60, 132, 60);
                e.DrawLine(new Pen(_EdgeColor, 5), 130, 60, 237, 21);
                e.DrawLine(new Pen(_EdgeColor, 5), 237, 21, 570, 21);
                e.DrawLine(new Pen(_EdgeColor, 5), 568, 21, 670, 60);
                e.DrawLine(new Pen(_EdgeColor, 5), 668, 60, 800, 60);
            }
            public Color EdgeColor
            {
                get { return _EdgeColor; }
                set { _EdgeColor = value; Invalidate(); }
            }
            [Browsable(false)]
            public override Size MaximumSize { get; set; }
            [Browsable(false)]
            public override Size MinimumSize { get; set; }
            [Browsable(false)]
            public override Color BackColor { get; set; }
            [Browsable(false)]
            public override Image BackgroundImage { get; set; }
            [Browsable(false)]
            public override ImageLayout BackgroundImageLayout { get; set; }
        }
    }

    Resulting Picture:


  • msdn3

    Besides making the properties “Browsable(true)” this is exactly what I would’ve done.

    Is there a reason on why it’s false?


  • msdn4

    I put it as false, so when it is dragged to a screen, the Visual Studio designer won’t give me the option of changing the properties. I have them set as static because I don’t want them to change. I would imagine it can still change in code, but that is not a big deal.


  • msdn5

    Ok.

    You can make them “readonly” or “constant” so they won’t be changeable at all if you want.

    Personally I would’ve liked to allow others to set them in the designer, but that’s just me 🙂


  • msdn6

    I can consider that, it may make sense to do it that way, so the user knows what is going on.

    Another quick question. I adjusted the code to allow for the color to change on the fly in runtime. Does anyone know of any performance related issues with this? Below is my new code, it is just what was modified, please refer to the code block above for the complete code that it is in.

    public Color EdgeColor
    {
        get { return _EdgeColor; }
        set { _EdgeColor = value; Invalidate(); Draw((this.CreateGraphics()) as Graphics); }
    }


  • msdn7

    I can consider that, it may make sense to do it that way, so the user knows what is going on.

    Another quick question. I adjusted the code to allow for the color to change on the fly in runtime. Does anyone know of any performance related issues with this? Below is my new code, it is just what was modified, please refer to the code block above for the complete code that it is in.

    public Color EdgeColor
    {
        get { return _EdgeColor; }
        set { _EdgeColor = value; Invalidate(); Draw((this.CreateGraphics()) as Graphics); }
    }

    Invalidate() raises OnPaint(), OnPaint() calls Draw(),You then call Draw() Again.

    If you set the same Color as was already set then you draw unnecessarily.

    Here’s a little modification:

    public Color EdgeColor
    {
      get
      {
        return this._EdgeColor;
      }
      set
      {
        if (this._EdgeColor != value)
        {
          this._EdgeColor = value;
          this.Invalidate();
        }
      }
    }

    …of course, this then adds an extra comparison every time the property is changed, but that is generrally cheaper than an unnecessary paint event.

    Realistically, unless you have lots of these panels on a form that are continuosly changing their edgecolor then it is a mute point as no is going to notice any speed issues with a single paint event which draws a very simple background.