How to set/change/remove focus style on a Button in C#? - c#

I have a couple of buttons of which I modified how they look. I have set them as flat buttons with a background and a custom border so they look all pretty and nothing like normal buttons anymore (actually, they look like Office 2003 buttons now ;-). The buttons have a border of one pixel.
However when the button gets selected (gets the focus through either a click or a keyboard action like pressing the tab key) the button suddenly gets and extra border around it of the same colour, so making it a two pixel border. Moreover when I disable the one pixel border, the button does not get a one pixel border on focus.
On the net this question is asked a lot like 'How can I disable focus on a Button', but that's not what I want: the focus should still exist, just not display in the way it does now.
Any suggestions? :-)

Is this the effect you are looking for?
public class NoFocusCueButton : Button
{
protected override bool ShowFocusCues
{
get
{
return false;
}
}
}
You can use this custom button class just like a regular button, but it won't give you an extra rectangle on focus.

I had the same issue with the annoying double border, and stumbled across this thread looking for an answer...
The way I solved this was to set the BorderSize to 0 then draw my own border in OnPaint
Note: Not the entire button, just the border
A simple example would be:
public class CustomButton : Button
{
public CustomButton()
: base()
{
// Prevent the button from drawing its own border
FlatAppearance.BorderSize = 0;
FlatStyle = System.Windows.Forms.FlatStyle.Flat;
}
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
// Draw Border using color specified in Flat Appearance
Pen pen = new Pen(FlatAppearance.BorderColor, 1);
Rectangle rectangle = new Rectangle(0, 0, Size.Width - 1, Size.Height - 1);
e.Graphics.DrawRectangle(pen, rectangle);
pen.Dispose();
}
}
In my case, this is how I made a button that mimics a ToolStripButton, where the border is only visible when you hover over the button:
public class ToolButton : Button
{
private bool ShowBorder { get; set; }
public ToolButton()
: base()
{
// Prevent the button from drawing its own border
FlatAppearance.BorderSize = 0;
// Set up a blue border and back colors for the button
FlatAppearance.BorderColor = Color.FromArgb(51, 153, 255);
FlatAppearance.CheckedBackColor = Color.FromArgb(153, 204, 255);
FlatAppearance.MouseDownBackColor = Color.FromArgb(153, 204, 255);
FlatAppearance.MouseOverBackColor = Color.FromArgb(194, 224, 255);
FlatStyle = System.Windows.Forms.FlatStyle.Flat;
// Set the size for the button to be the same as a ToolStripButton
Size = new System.Drawing.Size(23, 22);
}
protected override void OnMouseEnter(EventArgs e)
{
base.OnMouseEnter(e);
// Show the border when you hover over the button
ShowBorder = true;
}
protected override void OnMouseLeave(EventArgs e)
{
base.OnMouseLeave(e);
// Hide the border when you leave the button
ShowBorder = false;
}
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
// The DesignMode check here causes the border to always draw in the Designer
// This makes it easier to place your button
if (DesignMode || ShowBorder)
{
Pen pen = new Pen(FlatAppearance.BorderColor, 1);
Rectangle rectangle = new Rectangle(0, 0, Size.Width - 1, Size.Height - 1);
e.Graphics.DrawRectangle(pen, rectangle);
pen.Dispose();
}
}
// Prevent Text from being set on the button (since it will be an icon)
[Browsable(false)]
public override string Text { get { return ""; } set { base.Text = ""; } }
[Browsable(false)]
public override ContentAlignment TextAlign { get { return base.TextAlign; } set { base.TextAlign = value; } }
}

Make a custom button:
public partial class CustomButton: Button
{
public ButtonPageButton()
{
InitializeComponent();
this.SetStyle(ControlStyles.Selectable, false);
}
}
That'll get rid of that annoying border! ;-)

Another option (although a bit hacktastic) is to attach an event-handler to the button's GotFocus event. In that event-handler, pass a value of False to the button's NotifyDefault() method. So, for instance:
void myButton_GotFocus(object sender, EventArgs e)
{
myButton.NotifyDefault(false);
}
I'm assuming this will work every time, but I haven't tested it extensively. It's working for me for now, so I'm satisfied with that.

There is another way which works well for flat styled buttons. Don't use buttons but labels. As you are completely replacing the UI for the button it does not matter whether your use a button control or a label. Just handle the click in the same way.
This worked for me, although not great practice it is a good hack and as long as you name the button obviously (and comment the source) other coders will pick up the idea.
Ryan

The second border which gets added is the Windows standard "default button" border. You may have noticed that if you tab through most dialog boxes with multiple buttons (such as any Control Panel properties window), the original "double-bordered" button becomes "normal," and the in-focus button becomes "double-bordered."
This isn't necessarily focus at work, but rather a visual indication of the action undertaken by hitting the Enter key.
It sounds, to me, like you don't really care about that internal working. You want the display to not have two borders -- totally understandable. The internal working is to explain why you're seeing this behavior. Now ... To try and fix it.
The first thing I'd try -- and bear in mind, I haven't validated this -- is a hack. When a button receives focus (thereby getting the double-border), turn off your single border. You might get the effect you want, and it's pretty simple. (Hook into the Focus event. Even better, subclass Button and override OnFocus, then use that subclass for your future buttons.)
However, that might introduce new, awkward visual side effects. In that vein -- and because hacks are rarely the best answer -- I have to "officially" recommend what others have said: Custom paint the button. Although the code here may be overkill, this link at CodeProject discusses how to do that (VB link; you'll need translate). You should, in a full-on custom mode, be able to get rid of that second border completely.

Certainly you can draw the button yourself. One of the state flags is focused.
So on the draw event if the flag is focused go ahead and draw the button how you like, otherwise just pass it on to the base method.

Consider implementing your own drawing code for the button. That way you have full control. In the past, I've implemented my own Control derivative that custom paints my button and implements all the button characteristics for my purposes, but you should be able to override the button's painting and do it yourself, thereby controlling how it draws in every state, including when focused.

Set the FocusVisualStyle dependency property to null in your style, and the dotted border will be gone.
From MSDN: Styling for Focus in Controls, and FocusVisualStyle
Windows Presentation Foundation (WPF)
provides two parallel mechanisms for
changing the visual appearance of a
control when it receives keyboard
focus. The first mechanism is to use
property setters for properties such
as IsKeyboardFocused within the style
or template that is applied to the
control. The second mechanism is to
provide a separate style as the value
of the FocusVisualStyle property; the
"focus visual style" creates a
separate visual tree for an adorner
that draws on top of the control,
rather than changing the visual tree
of the control or other UI element by
replacing it. This topic discusses the
scenarios where each of these
mechanisms is appropriate.
The extra border you see is defined by the FocusVisualStyle and not in the control template, so you need to remove or override the style to remove the border.

If you have a textbox and a button
then on textchange event of textbox
write button1.focus();
It will work.

You can also create an invisible button and make it active whenever you press another button.

I've had good luck merely setting the Focusable property of the button to be false:
<Button HorizontalAlignment="Left" Margin="0,2"
Command="{Binding OpenSuspendedJobCommand, Mode=OneWay}"
Focusable="False"
Style="{StaticResource ActionButton}" Content="Open Job..." />

Related

C# Windows Form Application Transparent button

I'm new to C#. I'd like to create an invisible button, but they are click-able in C# windows form application. Is there a way? I tried BackColor to Transparent, but that does not change the fact that it is transparent
Its simple try this.
Click the button that you want to make transparent.
Select FlatStyle from Properties and set it to popup
Now change the BackColor property to Transparent.
This will make the button transparent.
However if you want to make it transparent over a PictureBox this method wont work..
It works only on normal backgrounds and background images.
Hope it works....
buttonLink.FlatStyle = FlatStyle.Flat;
buttonLink.BackColor = Color.Transparent;
buttonLink.FlatAppearance.MouseDownBackColor = Color.Transparent;
buttonLink.FlatAppearance.MouseOverBackColor = Color.Transparent;
The answers given just make the background color of the control you want to make transparent the same as the background color of its parent. It's not true transparency and windows forms doesn't support true transparency.
Windows Forms controls do not support true transparency. The background of a
transparent Windows Forms control is painted by its parent.
https://learn.microsoft.com/en-us/dotnet/desktop/winforms/controls/how-to-give-your-control-a-transparent-background?view=netframeworkdesktop-4.8&redirectedfrom=MSDN
Reference:
Original article and code can be found at:
Displaying a ToolTip when the Mouse Hovers Over a Disabled Control
# CodeProject by tetsushmz
Code:
public class TransparentSheet : ContainerControl
{
public TransparentSheet()
{
// Disable painting the background.
this.SetStyle(ControlStyles.Opaque, true);
this.UpdateStyles();
// Make sure to set the AutoScaleMode property to None
// so that the location and size property don't automatically change
// when placed in a form that has different font than this.
this.AutoScaleMode = AutoScaleMode.None;
// Tab stop on a transparent sheet makes no sense.
this.TabStop = false;
}
private const short WS_EX_TRANSPARENT = 0x20;
protected override CreateParams CreateParams
{
[SecurityPermission(SecurityAction.LinkDemand, UnmanagedCode = true)]
get
{
CreateParams l_cp;
l_cp = base.CreateParams;
l_cp.ExStyle = (l_cp.ExStyle | WS_EX_TRANSPARENT);
return l_cp;
}
}
}
Explanation:
What you need to do is use the given control as an overlay on your disabled TextBox (that you mentioned in one of your comments). Sibscribe to the overlay control's Click event and you have yourself a click on a disabled control.
I strongly recommend against this approach and feel it is kind of a hack. You really should look for an alternative approach instead of having to use a disabled control with an overlay control on top of it.
Maybe a different UI or atleast wrap it up in a UserControl to isolate this messy logic.
Setting the background property of the button to transparent will still leave a border. If you want a completely transparent button, do one of 2 things:
Create a transparent panel and assign a method to the Click event
or preferably
Create a custom UserControl that is filled with only BackColor (set to transparent) and assign method to Click event.
public class Invisible_Button : UserControl
{
protected override void OnMouseMove(MouseEventArgs e)
{
base.OnMouseMove(e);
this.Cursor = Cursors.Hand;
}
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
e.Graphics.FillRectangle(new SolidBrush(this.BackColor), 0, 0, this.Width, this.Height);
}
}
Did you try button.Visible = false?
If all you want is to hide it, this will do the job.

Change Border of ToolStripComboBox with Flat Style

I would like to be able to change the border color of ToolStripComboBox controls in some of my toolstrips, since the default border color of ComboBoxes when used with flat styling is SystemColors.Window, which is basically invisible against the default control color of the toolstrip. After a lot of digging around in Reflector, I don't see any obvious way to do this, since all the infrastructure behind ComboBox rendering is highly protected behind internal and private interfaces.
Outside of ToolStrips, a common solution I've seen proposed for fixing border color on ComboBoxes is to subclass ComboBox, override WndProc, and manually paint the border. This can't work for ToolStripComboBox controls since the internal ComboBox control is its own private subclass of ComboBox, with no way that I can see to replace the instance of the control.
An alternative solution I'm considering is putting one of the extended ComboBox objects into a ToolStripControlHost, which allows me to draw a border, but then I have to give up some of the professional renderer tweaks. A secondary drawback I've noticed is that I get occasional flicker during mouseover.
Switching my design to WPF is not an acceptable solution. Wrapping controls in parent controls for drawing borders is also not acceptable, as this gains nothing over the ToolStripControlHost alternative.
Does anyone have a clever solution to defeat this problem, or is there an existing (permissively-licensed) re-implementation of the ComboBox flat-style rendering stack out in the wild, which fixes some of the shortcomings in the existing implementation?
Here's a way to make it work ... sort of :)
Create an event handler for the Paint event of the ToolStrip. Then loop through all of the ToolStripComboBoxes and paint a rectangle around them.
private Color cbBorderColor = Color.Gray;
private Pen cbBorderPen = new Pen(SystemColors.Window);
private void toolStrip1_Paint(object sender, PaintEventArgs e)
{
foreach (ToolStripComboBox cb in toolStrip1.Items)
{
Rectangle r = new Rectangle(
cb.ComboBox.Location.X - 1,
cb.ComboBox.Location.Y - 1,
cb.ComboBox.Size.Width + 1,
cb.ComboBox.Size.Height + 1);
cbBorderPen.Color = cbBorderColor;
e.Graphics.DrawRectangle(cbBorderPen, r);
}
}
Here's what it looks like (note that you may need to adjust the Height of the ToolStrip to prevent the painted border from being cut off):
improvement:
check the type of the toolstrip item,
so the program will not crush if it is toolstipLabel for example.
foreach (var item in toolStrip1.Items)
{
var asComboBox = item as ToolStripComboBox;
if (asComboBox != null)
{
var location = asComboBox.ComboBox.Location;
var size = asComboBox.ComboBox.Size;
Pen cbBorderPen = new Pen(Color.Gray);
Rectangle rect = new Rectangle(
location.X - 1,
location.Y - 1,
size.Width + 1,
size.Height + 1);
e.Graphics.DrawRectangle(cbBorderPen, rect);
}
}
toolStrip1.ComboBox.FlatStyle = FlatStyle.System;
This sets the default, OS-styled, border around the combo box. It is a light grey and thin border on Windows 10. Although, depending on the background, this may not show. In which case, you could try the other options like FlatStyle.Popup.
If the presets aren't what you are looking for, the other answers allow you to draw a custom border. However, since the rectangle is drawn with +1 pixel size around the combo box, the border is 1 pixel larger than the combo box. Removing the +1s and -1s doesn't work either.

How to change the border color of a picturebox (winform)?

I want to set the border color/style around the picturebox on and off according to different events.
Are there properties or functions that help me to achieve that aim?
This has always been what I use for that:
To change the border color, call this from the Paint event handler of your Picturebox control:
private void pictureBox1_Paint_1(object sender, PaintEventArgs e)
{
ControlPaint.DrawBorder(e.Graphics, pictureBox1.ClientRectangle, Color.Red, ButtonBorderStyle.Solid);
}
To change the border color dynamically, for instance from a mouseclick event, I use the Tag property of the picturebox to store the color and adjust the Click event of the picturebox to retrieve it from there. For example:
if (pictureBox1.Tag == null) { pictureBox1.Tag = Color.Red; } //Sets a default color
ControlPaint.DrawBorder(e.Graphics, pictureBox1.ClientRectangle, (Color)pictureBox1.Tag, ButtonBorderStyle.Solid);
The picturebox Click event, then, would go something like this:
private void pictureBox1_Click(object sender, EventArgs e)
{
if ((Color)pictureBox1.Tag == Color.Red) { pictureBox1.Tag = Color.Blue; }
else {pictureBox1.Tag = Color.Red; }
pictureBox1.Refresh();
}
You'll need using System.Drawing; at the beginning and don't forget to call pictureBox1.Refresh() at the end. Enjoy!
Winforms doesn't let you change the border color of controls, they are fixed by the theme selected by the user. The easiest way to get what you want that doesn't require writing your own control is to put the picture box inside of a Panel, making it slightly smaller. Then just change the BackColor of the panel.
The designer will fight you a bit since it tries to align controls to a grid, edit the Location and Size properties in the Properties window directly rather than mousing it.
If you are talking about mouse events then MouseEnter and MouseLeave or MouseHover events can be utilized to do this and OnPaint event can be used to do the actual drawing. just invalidate the PictureBox on Above mentioned Mouse events or any event you care about.
Here is a simple example (in VB.NET, but it should be simple to convert it) that does this for you. You won't need to worry with using an extra Panel like with Passant's answer.

How do I get a disabled ToolStripButton to paint its image in colour?

We have a button which allows users to 'lock' a form. Users are not permitted to 'unlock' the form, so when pressed, we want the button to be disabled, so that the user receives appropriate visual feedback.
However, the customer reports that the greyed 'lock' icon suggests to them that the form is not locked, so we would like to display the button in a pressed state, but with the icon in colour, even though the button is disabled.
How do we do that, with the absolute minimum amount of overridden painting?
Actually I disagree with the approach. Your customer might have a valid point, but I don't think they have the correct suggestion for the fix. You should look into other ways to make the form appear "locked". Changing borders or font colours, having a big padlock icon appear or change from open to closed etc. Buttons look a certain way because that's what users expect. If you have a disabled button that looks like it might be enabled, that's going to confuse users who might not then understand why they can't click it.
You can set the ToolStripButton Image as BackgroundImage
and then set the DiplayStyle to None.
The picture should stay in colour no matter what's the button Enabled value.
I was in this case few weeks ago and this question doesn't have an answer, so this is my solution 4 years later :
I'm using this solution to repaint the ToolStripButton in many cases : disabled, checked, selected
override OnPaint event or change renderer of your ToolStrip
draw your image without grey filter with this method, just set the image of the button and image's position on your button : http://msdn.microsoft.com/en-us/library/chas0s9c(v=vs.110).aspx
Two good examples who helped me :
http://tutorials.csharp-online.net/Tool,_Menu,_and_Status_Strips%E2%80%94Customizing_a_Renderer
http://jskiles1.wordpress.com/2009/08/22/33/)
ToolStrip class :
ToolStrip ts = new ToolStrip();
//[...]
ts.RenderMode = ToolStripRenderMode.Professional; //Professional is just an example
ts.Renderer = new CustomRenderer();
CustomRenderer class :
public class CustomRenderer: ToolStripProfessionalRenderer
{
protected override void OnRenderButtonBackground(ToolStripItemRenderEventArgs e)
{
if (!e.Item.Enabled) //in this case you will just have the image in your button, you need to add text etc in this if
{
//to draw the image
Graphics g = e.Graphics;
g.DrawImageUnscaled(e.Item.Image, new Point(2, 2)); //you need to specify the correct position
}
else //other cases
base.OnRenderButtonBackground(e);
}
}
The problem is to know the correct position of all elements in your ToolStripButton , that's why I drawn the ToolStripButton in every cases
Another way: don't set the button.Enabled = false at all. Just set the button.Checked = true or false and when someone clicks on the button test for the Checked state and do whatever you do. The button will then function as you want and stay colored too.

RightToLeft property in Form in C#

I want to move the form title, icon and close, and help buttons from left side to right side (change the layout).
I moved the form controls manually to keep background image but now I want to change the form title.
When I set rightToLeft property to yes and rightToLeftLayout to true in the form properties the background image disappears, but it uses the property "BackColor"
My code is as follows:
if (_lang == 'Arabic')
{
this.RightToLeft = RightToLeft.Yes;
this.RightToLeftLayout = true;
}
But it keeps buttons image.
So why is that?
To further Blounty's answer, the MSDN specs clearly state that BackgroundImage, Opacity and others aren't supported when using RightToLeftLayout:
http://msdn.microsoft.com/en-us/library/system.windows.forms.form.righttoleftlayout(vs.80).aspx:
Owner draw is not supported when RightToLeftLayout is set to Yes. The owner draw events will still occur, but the behavior of any code you author in these events is not defined. Additionally, BackgroundImage, Opacity, TransparencyKey, and the painting events are not supported.
BackgroundImage, Opacity, TransparencyKey, and the painting events are not supported when RightToLeftLayout is set to yes.
It is pretty easy to replace the lost functionality:
protected override void OnPaintBackground(PaintEventArgs e) {
Rectangle rc = new Rectangle(Point.Empty, this.ClientSize);
e.Graphics.DrawImage(Properties.Resources.SampleImage, rc);
}
You'll need to do a bit more work if you need to tile the image.

Categories