Winforms - How do I create a custom windows border and close/minimise buttons?

I would like to be able to create a black custom window (with border and controls) like that shipped as part of expression blend, Twirl, or Adobe Lightroom.

Is there a best practices way of creating an owner drawn window?

Platform: C# and WindowsForms (any version)

Answers


Custom titlebars/chrome in a WinForms app


If the custom-chrome tools don't provide you with the look-and-feel that you want, this kind of thing is easy to do yourself in C#. Basically, you create a borderless form (FormBorderStyle = None) and then create all the controls and borders yourself, by placing controls where you need them (a label for the title bar, command buttons for close and minimize etc.) and/or drawing directly on the form's surface using the Graphics object.

You also have to implement code to allow the form to be dragged around by its "fake" title bar (see this answer for a sample of how to do this). You may also have to implement your own resizing mechanism (if you need the forms to be resizable).

Finally, although the custom-form code might be a bit clunky, you can implement it on a single form and then have all the other forms in your application inherit from this form, which makes it a very useful technique for custom-skinning an entire application.


My task was to make active window more noticeable, bright - than others, inactive windows of the app. App has many opened windows, some modal, some modeless - and the MDI parent one.

You can can use something like not-a-border - a frame inside the client area. Here is the code snippet, a part of a base class (can be used directly in a form):

    #region Кастомизированное поведение - рамки, активность и т.д.
    private bool isCurrentlyActive = false;
    private bool childControlsAreHandled = false;
    private Pen activeWindowFramePen, inactiveWindowFramePen;
    private Point[] framePoints;

    private void AddControlPaintHandler(Control ctrl)
    {
        ctrl.Paint += DrawWindowFrame;
        if (ctrl.Controls != null)
        {
            foreach (Control childControl in ctrl.Controls)
            {
                AddControlPaintHandler(childControl);
            }
        }
    }

    protected override void OnActivated(EventArgs e)
    {
        base.OnActivated(e);
        if ((this.childControlsAreHandled == false)
            && (WindowFrameType != Forms.WindowFrameType.NoFrame)
            && (this.MdiParent == null))
        {
            RecalculateWindowFramePoints();
            AddControlPaintHandler(this);
            this.childControlsAreHandled = true;
        }

        this.isCurrentlyActive = true;
        if (InactiveWindowOpacity < 1)
        {
            base.Opacity = 1;
        }
        base.Invalidate(true);
    }

    protected override void OnDeactivate(EventArgs e)
    {
        base.OnDeactivate(e);
        this.isCurrentlyActive = false;
        if (InactiveWindowOpacity < 1)
        {
            base.Opacity = InactiveWindowOpacity;
        }
        base.Invalidate(true);
    }

    protected override void OnResizeEnd(EventArgs e)
    {
        base.OnResizeEnd(e);
        this.framePoints = null;
        RecalculateWindowFramePoints();
        this.Invalidate(true);
    }

    private Pen ActivePen
    {
        get
        {
            if (this.isCurrentlyActive)
            {
                if (this.activeWindowFramePen == null)
                {
                    this.activeWindowFramePen = new Pen(Color.FromArgb((int)(WindowFrameOpacity*255), WindowFrameActiveColor), WindowFrameSize * 2);
                }
                return this.activeWindowFramePen;
            }
            else
            {
                if (this.inactiveWindowFramePen == null)
                {
                    this.inactiveWindowFramePen = new Pen(Color.FromArgb((int)(WindowFrameOpacity*255), WindowFrameInactiveColor), WindowFrameSize * 2);
                }
                return this.inactiveWindowFramePen;
            }
        }
    }

    private Point[] RecalculateWindowFramePoints()
    {
        if ((WindowFrameType == Forms.WindowFrameType.AllSides)
            && (this.framePoints != null)
            && (this.framePoints.Length != 5))
        {
            this.framePoints = null;
        }
        if ((WindowFrameType == Forms.WindowFrameType.LeftLine)
            && (this.framePoints != null)
            && (this.framePoints.Length != 2))
        {
            this.framePoints = null;
        }
        if (this.framePoints == null)
        {
            switch (WindowFrameType)
            {
                case Forms.WindowFrameType.AllSides:
                    this.framePoints = new Point[5]
                    {
                        new Point(this.ClientRectangle.X, this.ClientRectangle.Y),
                        new Point(this.ClientRectangle.X + this.ClientRectangle.Width, this.ClientRectangle.Y),
                        new Point(this.ClientRectangle.X + this.ClientRectangle.Width, this.ClientRectangle.Y + this.ClientRectangle.Height),
                        new Point(this.ClientRectangle.X, this.ClientRectangle.Y + this.ClientRectangle.Height),
                        new Point(this.ClientRectangle.X, this.ClientRectangle.Y)
                    };
                    break;
                case Forms.WindowFrameType.LeftLine:
                    this.framePoints = new Point[2]
                    {
                        new Point(this.ClientRectangle.X, this.ClientRectangle.Y),
                        new Point(this.ClientRectangle.X, this.ClientRectangle.Y + this.ClientRectangle.Height)
                    };
                    break;
            }
        }
        return this.framePoints;
    }

    private void DrawWindowFrame(object sender, PaintEventArgs e)
    {
        if (WindowFrameType == Forms.WindowFrameType.NoFrame)
        {
            return;
        }
        if ((this.framePoints == null) || (this.framePoints.Length == 0))
        {
            return;
        }
        Control ctrl = (Control)(sender);
        // пересчитаем точки в координатах контрола.
        List<Point> pts = new List<Point>();
        foreach (var p in this.framePoints)
        {
            pts.Add(ctrl.PointToClient(this.PointToScreen(p)));
        }
        e.Graphics.DrawLines(ActivePen, pts.ToArray());
    }

    public static int WindowFrameSize = 2;
    public static WindowFrameType WindowFrameType = Forms.WindowFrameType.NoFrame;
    public static Color WindowFrameActiveColor = Color.YellowGreen;
    public static Color WindowFrameInactiveColor = SystemColors.ControlDark;
    public static double InactiveWindowOpacity = 1.0;
    public static double WindowFrameOpacity = 0.3;
    #endregion

Static fields of the class are initialized from application settings form (class) - so, all the forms in the app has the same behavior.

Hope that helps to someone.


Need Your Help

Regexp in php matching two (or more) words in string

php regex

What I'm trying to do is to check if certain keywords are present in a string. Matching single words is not a problem, however I can't figure out how to get it to work if for example two words need...

Integrating PayPal checkout

paypal payment shop

I have a shop system that integrates PayPal in the usual way, i.e. the user is redirected to paypal.com to log in and confirm the payment after which the user is directed back at a confirmation pag...