Create custom UI appearance for WinForms RadioButton - part 3

July 9th, 2008 by ganton | Print

    (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.

      7 Responses to “Create custom UI appearance for WinForms RadioButton - part 3”

      1. Create custom UI appearance for WinForms CheckBox - part 2 : Anton Gochev’s Weblog Says:

        [...] Create custom UI appearance for WinForms RadioButton - part 3 [...]

      2. Create custom UI appearance for WinForms CustomButton - part 4 » Anton Gochev’s Weblog Says:

        [...] posts in this series: Post 1, Post 2, Post 3, Post 4, Post 5, Post 6, Source [...]

      3. Create custom UI appearance for WinForms controls - part 1 » Anton Gochev’s Weblog Says:

        [...] posts in this series: Post 1, Post 2, Post 3, Post 4, Post 5, Post 6, Source [...]

      4. whydzxx Says:

        thank you

      5. Maulik Says:

        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.

      6. ganton Says:

        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

      7. Maulik Says:

        Hello Anton,

        I used your code and that solved my problem. Great work !!!

        Thanks again.

      Leave a Reply