locked
Removing the focus rectangle from a flat button when the form itself does not have focus RRS feed

  • Pergunta

  • 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? 

    quinta-feira, 16 de abril de 2009 19:39

Respostas

  • 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.
    • Marcado como Resposta Bruce.Zhou sexta-feira, 24 de abril de 2009 08:17
    sexta-feira, 17 de abril de 2009 16:44

Todas as Respostas

  • 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.
    sexta-feira, 17 de abril de 2009 11:40
  • 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. 
    sexta-feira, 17 de abril de 2009 11:55
  • 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.
    • Editado Zhi-Xin Ye sexta-feira, 17 de abril de 2009 13:14 code
    sexta-feira, 17 de abril de 2009 13:12
  • 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.
    • Marcado como Resposta Bruce.Zhou sexta-feira, 24 de abril de 2009 08:17
    sexta-feira, 17 de abril de 2009 16:44
  • 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.
    • Marcado como Resposta Bruce.Zhou sexta-feira, 24 de abril de 2009 08:17
    • Não Marcado como Resposta nobugz sexta-feira, 24 de abril de 2009 09:53
    • Sugerido como Resposta Suthar Vishal quarta-feira, 16 de janeiro de 2013 09:37
    segunda-feira, 20 de abril de 2009 10:43
  • Try to ovverride "ShowFocusCues" property and make it false. it will remove remove focus rectangle from flat button

    public class ButtonEx : Button    
    {        
        protected override bool ShowFocusCues        
        {            
           get{return false;}        
        }    
    }

    quarta-feira, 20 de maio de 2015 09:33
  • above code not work in my project

    i am still getting border after focus on button

    My Button Code

    this.btnStockMstr.BackColor = System.Drawing.Color.Transparent;
                this.btnStockMstr.FlatAppearance.BorderSize = 0;
                this.btnStockMstr.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
                this.btnStockMstr.Font = new System.Drawing.Font("Microsoft Sans Serif", 12F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
                this.btnStockMstr.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(112)))), ((int)(((byte)(112)))), ((int)(((byte)(112)))));
                this.btnStockMstr.Image = global::Vandan.Properties.Resources.stock;
                this.btnStockMstr.ImageAlign = System.Drawing.ContentAlignment.MiddleLeft;
                this.btnStockMstr.Location = new System.Drawing.Point(0, 255);
                this.btnStockMstr.Margin = new System.Windows.Forms.Padding(4);
                this.btnStockMstr.Name = "btnStockMstr";
                this.btnStockMstr.Padding = new System.Windows.Forms.Padding(21, 0, 0, 0);
                this.btnStockMstr.Size = new System.Drawing.Size(323, 54);
                this.btnStockMstr.TabIndex = 2;
                this.btnStockMstr.Tag = "StockMstr";
                this.btnStockMstr.Text = "  Stock";
                this.btnStockMstr.TextImageRelation = System.Windows.Forms.TextImageRelation.ImageBeforeText;
                this.btnStockMstr.UseVisualStyleBackColor = true;

    quinta-feira, 13 de dezembro de 2018 02:59
  • your solution is simple and simply works for me. I am now working with visual studio 2019 for a WinForms app. Thanks @HansPassant
    • Editado tan hartono segunda-feira, 24 de fevereiro de 2020 04:34
    segunda-feira, 24 de fevereiro de 2020 04:33
  • Thanks Bruce! I did it in VB.Net too. 

        Public Overrides Sub NotifyDefault(value As Boolean)
            MyBase.NotifyDefault(False)
        End Sub
    terça-feira, 25 de fevereiro de 2020 02:11