Click here to Skip to main content
15,886,052 members
Articles / Programming Languages / C#
Article

Custom Button - Issues with Focus Border, Text Color, etc.

Rate me:
Please Sign up or sign in to vote.
4.86/5 (6 votes)
4 May 2012CPOL5 min read 46.6K   1.6K   20   5
MyButton is a simple .NET class for WinForms that helps in setting an image, drawing a rectangle while on focus, and taking care of the text of the button.

Introduction

MyButton is a simple .NET class for WinForms that helps in setting an image, drawing a rectangle while on focus, and taking care of the text of the button.

Background

Recently I was working on a project where I had to use images for buttons and rounded textboxes. Images for a button seemed to be simple but in my UpdateLayeredWindow, the default button component wasn't enough for all aspects. So I was using a third party library (Krypton Toolkit). That made my work very simple and easy. At the time of final version of the project, I thought to reduce the package size and the only thing I could eliminate was the third part library. I started developing a custom button and gradually got all the things working as was Krypton's button and my requirements. I had to do RnD on different sites for different tasks to get it working. So I thought why not share the whole thing in one place and help others who are kind of looking for the same or similar.

The solution

First we will need an image for the button background. You can pick up any image of any shape and/or size. The image I use is:

Button Background Image

Add the above image to the project. Create a component class named MyButton. Right click on your project, Add->Component, select Component Class, and name it MyButton. You should see the screen with the MyButton.cs file open as:

Initial Component Class

Click on "Click here to switch to code view", to switch to code view and actually start coding. Inherit your class from Button rather than the Component class. The initial code should look like this:

C#
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Drawing;

namespace MyComponentsPrj.components
// Your namescape an be anything. 
{
    public partial class MyButton : Button
    {
        public MyButton()
        {
            InitializeComponent();
        }

        public MyButton(IContainer container)
        {
            container.Add(this);

            InitializeComponent();
        }
    }
}

With the above code, we just have a newly developed component called MyButton of type Button. Yet, it doesn't have any special features. To add special features, first go to the Design mode of the MyButton class.

Button design settings

  • Select BackColor as Transparent - as we want the surrounding of the image to be transparent and not any different
  • Set the buttonBkgd.png added to the project as BackgroundImage
  • Set Hand as Cursor from the drop down
  • Select desired font
  • Select desired forecolor
  • Set UseVisualStyleBackColor to False
  • FlatAppearance: BorderColor should be None or not selected, BorderSize as 0, MouseDownBackColor and MouseOverBackColor as Transparent - we don't want a border around the button under any circumstance
  • Select FlatStyle as Flat

Note: If you have a custom color set for any Color property like ForeColor, BorderColor, etc., in Design mode then that won't be supportive. So it is better to define them in the constructor or as a separate method and call the method in both constructors. Like I call the below init(); in both the constructors:

C#
private void init()
{
    base.ForeColor = Color.FromArgb(0, 255, 254, 255);
    base.FlatAppearance.BorderColor = Color.FromArgb(0, 255, 255, 254);
    // Transparent border
}

With the above settings, the button will have a background, won't have any border around it, and all basic settings are set. If we don't add FlatAppearance.BorderColor then if our button has focus and some other application is active, then our button will look like this:

Border around Button when on focus but not active

Focus border

Now comes that solid inner border on the button when it has focus by navigating through the Tab key or otherwise. That bothers me. Well, I have two options: either don't support focus itself or have another sort of border. To remove the focus border, I override the following method in my class:

C#
/// <summary>
/// Avoids the inner solid rectangle shown on focus
/// </summary> 
protected override bool ShowFocusCues
{
    get
    {
        return false;
    }
}

With the above code added, the button won't show any indication when it has focus. Let's get the indication of focus by showing a dotted border instead of a solid line. For that, override onPaint() and implement the below code:

C#
protected override void OnPaint(PaintEventArgs pevent)
{
    base.OnPaint(pevent);

    // We want to draw dotted border only when the button has focus, not otherwise 
    if (base.ContainsFocus)
    {
        // Draw inner dotted rectangle when button is on focus
        Pen pen = new Pen(Color.Gray, 10);
        Point p = base.Location;
        pen.DashStyle = System.Drawing.Drawing2D.DashStyle.Dot;
        Rectangle rectangle = new Rectangle(4, 4, Size.Width - 8, Size.Height - 8);
        ControlPaint.DrawFocusRectangle(pevent.Graphics, rectangle);
        pen.Dispose();
    }
}

Hmmm, looks cool. Now we can also manage the focus issue and get an excellent inner dotted border when on focus. But, one more thing is bothering - when I click the button, the text turns to a Gray shade. This is Windows style, has no default property to set/change it. I want the ForeColor to be as it is and not change to gray or any other color. Different PCs with different themes may also affect this. I want my button to behave the same on each and every PC. Let's look at how to handle that issue.

Text color remains same on click

To achieve the goal, we will have to print the text manually and set the Text property to "". Create a property displayText which will be used in place of the Text property. Create a member variable textColor of type Color.

C#
private Color textColor = Color.White;

/// <summary>
/// Text used to display the contents rather than using Text property. 
/// </summary>         
public string displayText
{   get; set;  }

Add the following code at the bottom of onPaint():

C#
// Draw the string to screen
// Find the size of the text
SizeF sf = pevent.Graphics.MeasureString(displayText, this.Font, this.Width);
Point ThePoint = new Point();
// Get the center location to print the text 
ThePoint.X = (int)((this.Width / 2) - (sf.Width / 2));
ThePoint.Y = (int)((this.Height / 2) - (sf.Height / 2));

// Draw the text
//pevent.Graphics.DrawString(displayText, Font, new SolidBrush(textColor), ThePoint);
TextRenderer.DrawText(pevent.Graphics, displayText, Font, ThePoint, textColor);
this.Text = "";

Add ForeColorChanged event and add the code:

C#
/// <summary>
/// Whenever ForeColor is changed, the Alpha for the textColor
//  will also be changed and thus updated.
/// </summary>
private void MyButton_ForeColorChanged(object sender, EventArgs e)
{
    this.textColor = Color.FromArgb(255, ForeColor.R, ForeColor.G, ForeColor.B);
}

Wondering what is textColor doing and why it is used? Remember, I had said earlier that the custom colors are not completely supportive in setting any color. See the difference between the base.ForeColor and textColor settings. In base.ForeColor the Opacity is set to 0 whereas in textColor, the Opacity is set to 255. If you use just ForeColor to print text, then you might not see anything. Hence we need to change the opacity. With the above event, whatever the ForeColor is set to, our text will be printed properly without any doubt.

Why have I commented DrawString and used DrawText ? With DrawString, there was no spacing in between characters of the text. Using DrawText solved it. This may be due to the font and/or system. The Font that I have used is "Arial MT Bold". With the same settings on another system, DrawString had no issues whereas on my system I had. So you can use whichever suits you.

With this, the MyButton button component is complete. Rebuild your project and it is ready for use from the ToolBox. How to use it? Open a Form, drag the MyButton from ToolBox. If required, change properties else just add a text to display for the displayText property. Save it and execute your project. You can see the look and feel of the button remains the same when clicked or not. The dotted lined inner border appears when it has focus. Get rid of all other default borders.

Results of button on different cases:

Results of button

Points of iInterest

You can see how a single and easily developed component helped us override the default Windows style for the button and get the look and feel we wanted for our UI. The files for the MyButton class are included in the zip. Enjoy playing with it!

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior)
India India
I am a Freelance Software Developer and a Consultant. I provide service in Desktop, Client-Server, Database, Web and Mobile application developments. I like working on challenging projects and implementing new technologies and platforms.
I had started my career in IT development from DBase, COBOL, C and reached today to Java, C#, .NET, Android, BlackBerry (RIM), Windows Mobile, etc.

Comments and Discussions

 
GeneralMy vote of 4 Pin
sariqkhan21-Nov-12 1:34
sariqkhan21-Nov-12 1:34 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.