0

OK I have a custom Circular Button that I extended from Button class. See Below:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing.Drawing2D;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Drawing;

namespace CircleButton
{

public class CircleButton : Button
{
    private Color _fillColor = Color.Red;
    private Color _hoverColor = Color.Blue;


    [Category("Custom")]
    [Browsable(true)]
    [Description("Sets the fill color of the round button")]
    [Editor(typeof(System.Windows.Forms.Design.WindowsFormsComponentEditor), typeof(System.Drawing.Color))]
   public Color FillColor
    {
        set
        {
            this._fillColor = value;

        }
        get
        {
            return this._fillColor;

        }
    }

    [Category("Custom")]
    [Browsable(true)]
    [Description("Sets the Hover color of the round button")]
    [Editor(typeof(System.Windows.Forms.Design.WindowsFormsComponentEditor), typeof(System.Drawing.Color))]
    public Color HoverColor
    {
        set
        {
            this._hoverColor = value;


        }
        get
        {
            return this._hoverColor;
        }
    }


    protected override void OnPaint(PaintEventArgs pevent)
    {
        GraphicsPath gp = new GraphicsPath();
        gp.AddEllipse(0, 0, ClientSize.Width, ClientSize.Height);
        this.Region = new System.Drawing.Region(gp);
        base.OnPaint(pevent);
    }

    protected override void OnCreateControl()
    {
        this.FlatAppearance.MouseOverBackColor = this._hoverColor;
        this.FlatAppearance.BorderSize = 0;
        this.BackColor = this._fillColor;
        this.FlatStyle = FlatStyle.Flat;
        base.OnCreateControl();
    }  
}

Everthing works great in the Visual Studio Designer, but when I select the FillColor and HoverColor properties during design time, the colors on the design time control do not update.
Keep in mind that the colors DO show the appropriate change during runtime.

Maybe I am missing another directive or something? I have searched but unable to come up with an answer. I have spent 2 days on this.

This control is going to be distributed to another designer and needs to work properly during design time.

Any help would be most appreciated.

Dai
  • 141,631
  • 28
  • 261
  • 374
Jim Stewart
  • 1
  • 1
  • 2
  • 1
    You need to call `Invalidate()` which trigger the paint method – Ňɏssa Pøngjǣrdenlarp Nov 24 '18 at 23:47
  • See this (in a way simiilar) custom control: [Translucent circle with text](https://stackoverflow.com/questions/51396681/translucent-circle-with-text?answertab=active#tab-top). See the `NotifyPropertyChanged` handler (the `PropertyChanged?.Invoke()` is not relevant) and when/what properties call it. This a simple/functional method to refresh a control *look* when some properties are change at design-time. – Jimi Nov 24 '18 at 23:49

2 Answers2

0

I recommend reading these articles:

In short, you need to call Invalidate() in your property setters, as this triggers an eventual repaint (repaints are not immediate: a repaint request actually queues-up a repaint, so if two or more properties are set then the control will still only be repainted once (this is why UI properties must be set in the UI thread).

You should also perform equality checks in property setters to prevent unnecessary repainting, like so:

[Category("Custom")]
[Browsable(true)]
[Description("Sets the Hover color of the round button")]
[Editor(typeof(System.Windows.Forms.Design.WindowsFormsComponentEditor), typeof(System.Drawing.Color))]
public Color HoverColor
{
    get
    {
        return this._hoverColor;
    }
    set
    {
        if( this._hoverColor != value )
        {
            this._hoverColor = value;
            this.Invalidate();
        } 
    }
}

(Style-tip: In recent years the C# developer ecosystem (and Microsoft too) have started to use _underscore-prefixed identifiers only for static fields and normal camelCase for instance fields, but always accessed with this., so I would change this._hoverColor to this.hoverColor).

Dai
  • 141,631
  • 28
  • 261
  • 374
  • It should be noted that this works for solid colors only and not in any occasion. For example, take the class that I posted in the OP's comments. Using just `Invalidate()` on a property change, the colors won't be updated correctly. You'ld have to click on the Form for the update to complete. It would require a different custom designer attached to the class to work as intended. – Jimi Nov 25 '18 at 00:09
  • @Jimi In the "Translucent circle with text" example, the `BackColor` property belongs to `Label` and not the custom control subclass, so `Label` could still be doing stuff behind-the-scenes to trigger a live update in the designer. – Dai Nov 25 '18 at 00:34
  • The BackColor property is overridden, `base` is not called and the Custom Label doesn't have a background color, it's not even painted (`ControlStyles.Opaque` + `WS_EX_TRANSPARENT`). But you'ld have the same result with a system-painted background and also setting `base.BackColor` with this Color type (`ControlStyles.SupportsTransparentBackColor`). The Text property wouldn't be updated correctly, too (at design-time). – Jimi Nov 25 '18 at 00:41
  • Unfortunately, Invalidate() does nothing. I tried it again. (I forgot to mention that I had already tried this) but still nothing. I DID add the equality check though, it was great suggestion. – Jim Stewart Nov 25 '18 at 02:12
  • 1
    @JimStewart You may need to rebuild your project and/or restart Visual Studio (if your control is in a loaded library instead of your active project). – Dai Nov 25 '18 at 02:14
  • I finally solved it. I don't know if this is the correct way to do it, but it works. – Jim Stewart Nov 25 '18 at 02:20
0

Ok so I finally solved it by changing the property in the setter, while adding the Invalidate() Method:

if (this._fillColor != value)
            {
                this._fillColor = value;
                this.BackColor = this._fillColor;  ///<--Added this line worked
                this.Invalidate();
            }

Thank you for your great suggestions and answers, I truly appreciate your help!

Jim Stewart
  • 1
  • 1
  • 2