Create custom UI appearance for WinForms RadioButton - part 3
(All posts in this series: Post 1, Post 2, Post 3, Post 4, Post 5, Post 6, Source Code)
It is my third post of WinForms controls with custom UI appearance. Here I’ll provide a custom radio button. For its implementation I’ll use CustomCheckBoxUIAppearance from my old post. As with CustomCheckBox (see my old post) it will be used for configuring UI appearance of the radio button. Both CustomCheckBox and CustomRadioButton controls are quite similar. Consequently, all have been said for CustomCheckBox control is valid for CustomRadioButton control. It is for sure that there are some differences :). The first one is that CustomRadioButton inherites from standard RadioButton (line 3) instead of CheckBox. The second difference is that here in OnPaint method we’ll use FillEllipse and DrawEllipse in order to paint radio button circle and its tick (line 79 -97). The third one is that we will use CustomCheckBoxUIAppearance’s TickThicness in some different way that it has been used in CustomCheckBox. When CustomRadioButton’s state is checked we’ll fill a small circle (our tick) into the external circle (line 86 - 89). Using TickThicness value we’ll correct tick’s yield to external circle border. This way we are able to provide diffferent look of our radio button.
Here’s the implementation of CustomRadioButton control.
[sourcecode language="csharp"]
public class CustomRadioButton : RadioButton
{
private CustomCheckBoxUIAppearance _customAppearance;
private bool _enableCustomUIAppearance;
[Description("If true control's is drawn using custom UI appearance, otherwise it appears using standard drawing."), Category("Custom Appearance"),
DefaultValue(true), DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
public bool EnableCustomUIAppearance
{
get { return _enableCustomUIAppearance; }
set
{
if (_enableCustomUIAppearance != value)
{
_enableCustomUIAppearance = value;
if (AutoSize)
{
AutoSize = false;
}
Invalidate();
}
}
}
[Description("This property specifies the way of drawing the control."), Category("Custom Appearance"),
DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
public CustomCheckBoxUIAppearance CustomAppearance
{
get { return _customAppearance; }
}
public CustomRadioButton()
{
_enableCustomUIAppearance = true;
_customAppearance = new CustomCheckBoxUIAppearance(this);
}
protected override void OnPaint(PaintEventArgs pevent)
{
// Call base class’ OnPaint
base.OnPaint(pevent);
if (!_enableCustomUIAppearance)
{
return;
}
// padding of the standard RadioButton
int offset = 2;
// distance betwen RadioButton area and included label
int distance = 5;
int radioButtonWidthHeight = 12;
Graphics graphics = pevent.Graphics;
graphics.Clear(BackColor);
// get Text measure according to selected Font
SizeF stringMeasure = graphics.MeasureString(Text, Font);
// Set graphics object to paint nice using antialias.
if (_customAppearance.EnableAntiAlias)
{
graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
graphics.TextRenderingHint = System.Drawing.Text.TextRenderingHint.ClearTypeGridFit;
}
// calculate offsets
int leftOffset = offset + Padding.Left;
int topOffset = (int)(ClientRectangle.Height - stringMeasure.Height) / 2;
if (topOffset < 0)
{
topOffset = offset + Padding.Top;
}
else
{
topOffset += Padding.Top;
}
if (Checked)
{
// Fill circle of the radio button
graphics.FillEllipse(new SolidBrush(_customAppearance.CheckedBackColor), leftOffset, topOffset, radioButtonWidthHeight, radioButtonWidthHeight);
// Draw circle of the radio button
graphics.DrawEllipse(new Pen(_customAppearance.CheckedBorderColor, _customAppearance.BorderThicness), leftOffset, topOffset, radioButtonWidthHeight, radioButtonWidthHeight);
// Fill circle of the radio button tick
int internalCircleWidthHeight = radioButtonWidthHeight - _customAppearance.BorderThicness * 2 - _customAppearance.TickThickness * 2;
int internalCircleOffset = _customAppearance.BorderThicness + _customAppearance.TickThickness;
graphics.FillEllipse(new SolidBrush(_customAppearance.TickColor), leftOffset + internalCircleOffset,
topOffset + internalCircleOffset, internalCircleWidthHeight, internalCircleWidthHeight);
}
else
{
// Fill circle of the radio button
graphics.FillEllipse(new SolidBrush(_customAppearance.BackColor), leftOffset, topOffset, radioButtonWidthHeight, radioButtonWidthHeight);
// Draw circle of the radio button
graphics.DrawEllipse(new Pen(_customAppearance.BorderColor, _customAppearance.BorderThicness), leftOffset, topOffset, radioButtonWidthHeight, radioButtonWidthHeight);
}
graphics.DrawString(Text, Font, new SolidBrush(ForeColor), leftOffset + radioButtonWidthHeight + distance, topOffset);
}
protected override void OnAutoSizeChanged(EventArgs e)
{
if (_enableCustomUIAppearance)
{
if (AutoSize)
{
AutoSize = false;
}
}
base.OnAutoSizeChanged(e);
}
}
[/sourcecode]
Below is the output of CustomRadioButton in different configuration.

July 11th, 2008 at 4:46 pm
[...] Create custom UI appearance for WinForms RadioButton - part 3 [...]
July 31st, 2008 at 3:07 pm
[...] posts in this series: Post 1, Post 2, Post 3, Post 4, Post 5, Post 6, Source [...]
July 31st, 2008 at 3:10 pm
[...] posts in this series: Post 1, Post 2, Post 3, Post 4, Post 5, Post 6, Source [...]
August 6th, 2008 at 4:37 am
thank you
March 5th, 2009 at 2:38 pm
Hello Anton,
First of all thanks for your nice work. I appreciate your work.
Now, I found one problem while using radiobutton code. Description is given bellow.
In AutoSize = true mode if you assign radiobutton’s Text property to more then 60 characters string. Text is trimmed from right side. Please guide me how to solve this problem ?
To replicate this problem just do some change in above code..
protected override void OnAutoSizeChanged(EventArgs e)
{
if (_enableCustomUIAppearance)
{
////Set AutoSize to false.
//if (AutoSize)
//{
// AutoSize = false;
//}
}
base.OnAutoSizeChanged(e);
}
After this just build dll and use it in application. You can see the problem.
Control is working fine when text is less then 55 characters. I particularly want to set AutoSize = true because in my application i want to generate controls at runtime.
Thanks.
March 6th, 2009 at 12:54 am
Hi Maulik,
Initially, I extended standard RadioButton in order ust to change its default appearance without controlling the auto size because the base class OnPaint will change all my estimations if AutoSize mode is on. That is why it works only in non AutoSize mode.
I can offer you a simple work around that is not very elegant but it may help you to use the control in AutoSize mode.
You need to override AutoSize property in order to suspend original RadioButton logic when custom appearance is activated and to allow original logic when custom appearance is not activated.
private bool _customAutoSize = false;
public override bool AutoSize
{
get
{
if (!_enableCustomUIAppearance)
{
return base.AutoSize;
}
return _customAutoSize;
}
set
{
if (!_enableCustomUIAppearance)
{
base.AutoSize = value;
}
else if (_customAutoSize != value)
{
_customAutoSize = value;
Invalidate();
}
}
}
Than you can simply extend the OnPaint method adding the code below before calculate offset comment.
if (_customAutoSize)
{
Width = (int)((stringMeasure.Width + Padding.Left + Padding.Right + offset + distance + radioButtonWidthHeight) + 0.5);
Height = (int)((stringMeasure.Height + Padding.Top + Padding.Bottom + offset) + 0.5);
}
Then remove the else statement of calculate offsets and you also should remove OnAutoSizeChanged. Please remove setting of AutoSize in EnableCustomUIAppearance property.
Regards,
Anton
March 6th, 2009 at 10:28 am
Hello Anton,
I used your code and that solved my problem. Great work !!!
Thanks again.