none
Removing the focus rectangle from a flat button when the form itself does not have focus

    Question

  • I have a windows forms app that has some flat, borderless buttons, and I noticed that while the focus rectangle does not appear when the window has focus, as soon as another window has focus, but my window is still visible, the rectangle appears.  For a sample, try this in a plain winforms app:

            public Form1()
            {
                InitializeComponent();
                Button b = new Button();
                b.Text = "Button Text";
                b.Width = 100;
                b.Height = 100;
                b.FlatStyle = FlatStyle.Flat;
                b.FlatAppearance.BorderSize = 0;
                b.FlatAppearance.BorderColor = Color.Red;
                b.BackColor = Color.Transparent;
                Controls.Add(b);
            }     
    If you click the button when the window has focus, everything looks OK, but if you change the OS focus to another application, a border appears.  I haven't found a property yet to get rid of this (I tried my own button class with an override to set EnableVisualCues set to false)-is there a way to get rid of the rectangle when your app does not have focus? 

    Thursday, April 16, 2009 7:39 PM

Answers

  • Tricky problem, it took me a while.  The button's IsDefault property changes.  Not 100% sure if that's a bug, although it quacks like one.  The fix is easy.  Add a new class to your project and paste the code shown below.  Compile.  Drop the button from the top of the toolbox onto your form.

    using System;
    using System.Windows.Forms;

    public class MyButton : Button {
      public override void NotifyDefault(bool value) {
        base.NotifyDefault(false);
      }
    }
    Hans Passant.
    • Marked as answer by Bruce.Zhou Friday, April 24, 2009 8:17 AM
    Friday, April 17, 2009 4:44 PM

All replies

  • Hi Chris,

    I can reproduce the problem, you can set the value of  BorderColor property to the same as the back color of the form to "remove" the focus rectangle.

    b.FlatAppearance.BorderColor = this.BackColor;

    If you have any questions or concerns, please feel free to let me know.

    Best Regards,
    Zhi-Xin Ye

    Please remember to mark the replies as answers if they help and unmark them if they provide no help.
    Welcome to the All-In-One Code Framework! If you have any feedback, please tell us.
    Friday, April 17, 2009 11:40 AM
  • Thanks for the reply-I actually already tried that, and while it works for this test application, it doesn't work for my actual app, since in that case, the background is a gradient.  I also tried setting the border color to transparent, but this throws an exception.  I suppose I could subclass button and make it so that transparent is a supported color (I seem to remember doing this before-I'd have to look it up), but that seems like overkill.  It might be necessary if there's no other way though. 
    Friday, April 17, 2009 11:55 AM
  • Hi Chris,

    Subclassing the button and override the OnPaint method is OK, however, it costs lots of work. I've another two ideas:

    1. Put the Button in a UserControl? We can change the size and location of the button to make the UserControl overlaps the Button, so we won't see the border at all, for example, define a UserControl as follows, and drag it on to a form, run the program to see the result.

    public class ButtonWithoutBorder : UserControl
        {
            public ButtonWithoutBorder()
            {
                this.BackColor = Color.Transparent;
                b.BackColor = Color.Transparent;
                b.FlatStyle = FlatStyle.Flat;
                b.FlatAppearance.BorderSize = 0;
                b.Text = "Button Text";
               
                b.Size = new Size(this.Width + 2, this.Height + 2);
                b.Location = new Point(-1, -1);

                this.Controls.Add(b);
            }

            Button b = new Button();

            protected override void OnResize (EventArgs e)
            {
                b.Size = new Size(this.Width + 2, this.Height + 2);
                base.OnResize(e);
            }
        }


    2. Use a Label instead, and handle its MouseDown/MouseEnter/MouseLeave events to change the back color.

    Please let me know if my suggestions make sense to you.

    Best Regards,
    Zhi-Xin Ye



    Please remember to mark the replies as answers if they help and unmark them if they provide no help.
    Welcome to the All-In-One Code Framework! If you have any feedback, please tell us.
    • Edited by Zhi-Xin Ye Friday, April 17, 2009 1:14 PM code
    Friday, April 17, 2009 1:12 PM
  • Tricky problem, it took me a while.  The button's IsDefault property changes.  Not 100% sure if that's a bug, although it quacks like one.  The fix is easy.  Add a new class to your project and paste the code shown below.  Compile.  Drop the button from the top of the toolbox onto your form.

    using System;
    using System.Windows.Forms;

    public class MyButton : Button {
      public override void NotifyDefault(bool value) {
        base.NotifyDefault(false);
      }
    }
    Hans Passant.
    • Marked as answer by Bruce.Zhou Friday, April 24, 2009 8:17 AM
    Friday, April 17, 2009 4:44 PM
  • Good finding!  The button's IsDefault property changes.  Seems this is by design, I find the code in Reflector shows this:


    void PaintUp(PaintEventArgs e, CheckState state)
    {
    .....
     if ((!base.Control.IsDefault || !base.Control.Focused) || (base.Control.FlatAppearance.BorderSize != 0))
        {
            ButtonBaseAdapter.DrawDefaultBorder(g, clientRectangle, colors.windowFrame, base.Control.IsDefault);
        }
    ...
    }

    ivoid DrawDefaultBorder(Graphics g, Rectangle r, Color c, bool isDefault)
    {
        if (isDefault)
        {
            Pen pen;
            r.Inflate(1, 1);
           .......
        }
    }


    When the button is selected, it becomes the default button, and when the form is deactived, the button's Focused property is false, so by the logic shows above, the default button border is drawn.

    Best Regards,




    Please remember to mark the replies as answers if they help and unmark them if they provide no help.
    Welcome to the All-In-One Code Framework! If you have any feedback, please tell us.
    Monday, April 20, 2009 10:43 AM