Click here to Skip to main content
15,881,715 members
Please Sign up or sign in to vote.
1.00/5 (1 vote)
I've got a custom control, "ButtonControl", which contains a property of a custom class "Corners". This class has four properties of the custom class "Corner", which has a value for the angle and the radius of a corner (both type int). Whenever I rebuild the solution, the properties window in the designer shows the message "Object does not match target type." for each "Corner" property of the "Corners" property. When I reopen the solution everything works fine.
I've added the code to github: https://github.com/Willunsnix/ASD-Root

Can somebody please point me in the right direction?

Below the code for Corner.cs
using System;
using System.Collections;
using System.ComponentModel;
using System.Globalization;

namespace ASD.Drawing.Properties
{
    [TypeConverter(typeof(CornerConverter))]
    public class Corner : IEquatable<Corner>
    {
        #region Private Members

        private const int DEFAULT_ANGLE = 90;
        private const int DEFAULT_RADIUS = 0;

        private int _angle = DEFAULT_ANGLE;
        private int _radius = DEFAULT_RADIUS;

        private bool ShouldSerializeAngle()
        {
            return _angle != DEFAULT_ANGLE;
        }

        private void ResetAngle()
        {
            Angle = DEFAULT_ANGLE;
        }

        private bool ShouldSerializeRadius()
        {
            return _radius != DEFAULT_RADIUS;
        }

        private void ResetRadius()
        {
            Radius = DEFAULT_RADIUS;
        }

        #endregion Private Members

        #region Constructors

        public Corner()
        {
            Angle = DEFAULT_RADIUS;
            Radius = 0;
        }

        public Corner(int angle, int radius)
        {
            Angle = angle > 0 ? angle : DEFAULT_RADIUS;
            Radius = radius > 0 ? radius : 0;
        }

        #endregion Constructors

        #region Properties

        [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
        [RefreshProperties(RefreshProperties.Repaint)]
        [NotifyParentProperty(true)]
        //[DefaultValue(90)]
        [Description("Angle of the corner.")]
        public int Angle
        {
            get { return _angle; }
            set { _angle = value; }
        }

        [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
        [RefreshProperties(RefreshProperties.Repaint)]
        [NotifyParentProperty(true)]
        //[DefaultValue(0)]
        [Description("Radius of the corner")]
        public int Radius
        {
            get { return _radius; }
            set { _radius = value; }
        }

        #endregion Properties

        #region Methods

        public override bool Equals(object obj) => this.Equals(obj as Corner);

        public bool Equals(Corner p)
        {
            if (p is null)
            {
                return false;
            }

            // Optimization for a common success case.
            if (Object.ReferenceEquals(this, p))
            {
                return true;
            }

            // If run-time types are not exactly the same, return false.
            if (this.GetType() != p.GetType())
            {
                return false;
            }

            // Return true if the fields match.
            // Note that the base class is not invoked because it is
            // System.Object, which defines Equals as reference equality.
            return (Angle == p.Angle) && (Radius == p.Radius);
        }

        public override int GetHashCode() => (Angle, Radius).GetHashCode();

        public static bool operator ==(Corner lhs, Corner rhs)
        {
            if (lhs is null)
            {
                if (rhs is null)
                {
                    return true;
                }

                // Only the left side is null.
                return false;
            }
            // Equals handles case of null on right side.
            return lhs.Equals(rhs);
        }

        public static bool operator !=(Corner lhs, Corner rhs) => !(lhs == rhs);

        public override string ToString()
        {
            return $"[{Angle.ToString().Trim()}:{Radius.ToString().Trim()}]";
        }

        #endregion Methods

        public partial class CornerConverter : ExpandableObjectConverter
        {
            public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
            {
                if (ReferenceEquals(sourceType, typeof(string)))
                {
                    return true;
                }
                // Allow conversion from string
                return base.CanConvertFrom(context, sourceType);
            }

            public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
            {
                if (ReferenceEquals(value.GetType(), typeof(string)))
                {
                    // Conversion from
                    var stringArray = value.ToString().Replace("[", "").Replace("]", "").Split(':');
                    //var stringArray = value.ToString().Split(':');

                    if (stringArray.Length >= 2)
                    {
                        if (int.TryParse(stringArray[0], out int angle) && int.TryParse(stringArray[1], out int radius))
                        {
                            return new Corner(angle, radius);
                        }
                    }

                    throw new FormatException();
                }

                return base.ConvertFrom(context, culture, value);
            }

            // Overrides the ConvertTo method of TypeConverter.
            public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType)
            {
                if (destinationType == typeof(string))
                {
                    //return ((Corner)value).Angle + ":" + ((Corner)value).Radius;
                    return $"[{((Corner)value).Angle}:{((Corner)value).Radius}]";
                }
                return base.ConvertTo(context, culture, value, destinationType);
            }

            public override bool GetCreateInstanceSupported(ITypeDescriptorContext context)
            {
                //Alway force a new instance
                return true;

                //Original default statement
                //return base.GetCreateInstanceSupported(context);
            }

            public override object CreateInstance(ITypeDescriptorContext context, IDictionary propertyValues)
            {
                //Use the dictionary to create a new instance
                return new Corner((int)propertyValues["Angle"], (int)propertyValues["Radius"]);

                //Original default statement
                //return base.CreateInstance(context, propertyValues);
            }

            public override bool GetPropertiesSupported(ITypeDescriptorContext context)
            {
                return true;
            }

            public override PropertyDescriptorCollection GetProperties(ITypeDescriptorContext context, object value, Attribute[] attributes)
            {
                return TypeDescriptor.GetProperties(typeof(Corner));
            }
        }
    }
}


Next the code for Corners.cs:
using System;
using System.Collections;
using System.ComponentModel;
using System.Globalization;

namespace ASD.Drawing.Properties
{
    [TypeConverter(typeof(Converter))]
    public class Corners
    {
        #region Private Members
        private Corner _topLeft = new Corner();
        private Corner _topRight = new Corner();
        private Corner _bottomLeft = new Corner();
        private Corner _bottomRight = new Corner();

        private Corner GetCornerFromString(string cornerString)
        {
            var cornerArray = cornerString.Trim().Replace("[", "").Replace("]", "").Split(':');

            if (cornerArray.Length >= 2)
            {
                if (int.TryParse(cornerArray[0], out int angle) && int.TryParse(cornerArray[1], out int radius))
                {
                    return new Corner(angle, radius);
                }
            }
            throw new FormatException();
        }

        private bool ShouldSerializeTopLeft()
        {
            return _topLeft != new Corner();
        }

        private void ResetTopLeft()
        {
            TopLeft = new Corner();
        }

        private bool ShouldSerializeTopRight()
        {
            return _topRight != new Corner();
        }

        private void ResetTopRight()
        {
            TopRight = new Corner();
        }

        private bool ShouldSerializeBottomRight()
        {
            return _bottomRight != new Corner();
        }

        private void ResetBottomRight()
        {
            BottomRight = new Corner();
        }

        private bool ShouldSerializeBottomLeft()
        {
            return _bottomLeft != new Corner();
        }

        private void ResetBottomLeft()
        {
            BottomLeft = new Corner();
        }

        #endregion Private Members

        #region Constructors

        public Corners()
        {
            TopLeft = new Corner();
            TopRight = new Corner();
            BottomLeft = new Corner();
            BottomRight = new Corner();
        }

        public Corners(Corner topLeft, Corner topRight, Corner bottomRight, Corner bottomLeft)
        {
            TopLeft = topLeft;
            TopRight = topRight;
            BottomLeft = bottomRight;
            BottomRight = bottomLeft;
        }

        public Corners(string allCornersText)
        {
            string[] cornerTextArray = allCornersText.Split(':');
            if (cornerTextArray.Length >= 4)
            {
                Corner[] corners = new Corner[4];

                for (int i = 0; i < 4; i++) { corners[i] = GetCornerFromString(cornerTextArray[i]); }

                TopLeft = corners[0];
                TopRight = corners[1];
                BottomLeft = corners[2];
                BottomRight = corners[3];
            }
            else
            {
                throw new FormatException();
            }
        }

        public Corners(string topLeft, string topRight, string bottomRight, string bottomLeft)
        {
            TopLeft = GetCornerFromString(topLeft);
            TopRight = GetCornerFromString(topRight);
            BottomLeft = GetCornerFromString(bottomRight);
            BottomRight = GetCornerFromString(bottomLeft);
        }

        #endregion Constructors

        #region Properties

        [Browsable(true)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        [RefreshProperties(RefreshProperties.Repaint)]
        [NotifyParentProperty(true)]
        [Description("Border settings for top left corner")]
        public Corner TopLeft
        {
            get { return _topLeft; }
            set { _topLeft = value; }
        }

        //[Browsable(true)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        [RefreshProperties(RefreshProperties.Repaint)]
        [NotifyParentProperty(true)]
        [Description("Border settings for top right corner")]
        public Corner TopRight
        {
            get { return _topRight; }
            set { _topRight = value; }
        }

        //[Browsable(true)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        [RefreshProperties(RefreshProperties.Repaint)]
        [NotifyParentProperty(true)]
        [Description("Border settings for bottom right corner")]
        public Corner BottomRight
        {
            get { return _bottomRight; }
            set { _bottomRight = value; }
        }

        //[Browsable(true)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        [RefreshProperties(RefreshProperties.Repaint)]
        [NotifyParentProperty(true)]
        [Description("Border settings for bottom left corner")]
        public Corner BottomLeft
        {
            get { return _bottomLeft; }
            set { _bottomLeft = value; }
        }

        #endregion Properties

        #region Methods
        public void CopyAngles(Corners source)
        {
            _topLeft.Angle = source.TopLeft.Angle;
            _topRight.Angle = source.TopRight.Angle;
            _bottomLeft.Angle = source.BottomLeft.Angle;
            _bottomRight.Angle = source.BottomRight.Angle;
        }

        public void CopyRadiuses(Corners source)
        {
            _topLeft.Radius = source.TopLeft.Radius;
            _topRight.Radius = source.TopRight.Radius;
            _bottomLeft.Radius = source.BottomLeft.Radius;
            _bottomRight.Radius = source.BottomRight.Radius;
        }

        public void ResetAngles()
        {
            _topLeft.Angle = 90;
            _topRight.Angle = 90;
            _bottomLeft.Angle = 90;
            _bottomRight.Angle = 90;
        }

        public void ResetCorners()
        {
            _topLeft = new Corner();
            _topRight = new Corner();
            _bottomLeft = new Corner();
            _bottomRight = new Corner();
        }

        public void ResetRadiuses()
        {
            _topLeft.Radius = 0;
            _topRight.Radius = 0;
            _bottomLeft.Radius = 0;
            _bottomRight.Radius = 0;
        }

        public bool ValidAngles()
        {
            return (_topLeft.Angle + _topRight.Angle + _bottomLeft.Angle + _bottomRight.Angle) == 360;
        }

        public override string ToString()
        {
            return $"{TopLeft.ToString().Trim()};{TopRight.ToString().Trim()};{BottomLeft.ToString().Trim()};{BottomRight.ToString().Trim()}";
        }

        #endregion Methods

        public partial class Converter : ExpandableObjectConverter
        {
            public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
            {
                if (ReferenceEquals(sourceType, typeof(string)))
                {
                    return true;
                }
                // Allow conversion from string
                return base.CanConvertFrom(context, sourceType);
            }

            public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
            {
                if (ReferenceEquals(value.GetType(), typeof(string)))
                {
                    // Conversion from string
                    var stringArray = value.ToString().Split(';');
                    bool isValid = true;
                    string message = string.Empty;

                    if (stringArray.Length >= 4)
                    {
                        Corner[] corners = new Corner[4];
                        for (int i = 0; i < 4 && isValid; i++)
                        {
                            //var cornerString = stringArray[i].Replace("[", "").Replace("]", "").Split(':');
                            var cornerString = stringArray[i].Split(':');
                            if (int.TryParse(cornerString[0], out int angle) && int.TryParse(cornerString[1], out int radius))
                            {
                                corners[i] = new Corner(angle, radius);
                            }
                            else
                            {
                                isValid = false;
                                message = "Parsing of the corner[" + i.ToString() + "] failed!";
                            }
                        }

                        if (isValid) return new Corners(corners[0], corners[1], corners[2], corners[3]);
                    }
                    else message = "Not enough parameters in string value, or wrong separator used in splitting the value!";

                    throw new FormatException(message);
                }

                return base.ConvertFrom(context, culture, value);
            }

            public override bool GetCreateInstanceSupported(ITypeDescriptorContext context)
            {
                //Alway force a new instance
                return true;

                //Original default statement
                //return base.GetCreateInstanceSupported(context);
            }

            public override object CreateInstance(ITypeDescriptorContext context, IDictionary propertyValues)
            {
                //Use the dictionary to create a new instance
                //return new Corners((Corner)propertyValues["TopLeft"], (Corner)propertyValues["TopRight"], (Corner)propertyValues["BottomRight"], (Corner)propertyValues["BottomLeft"]);

                //Original default statement
                return base.CreateInstance(context, propertyValues);
            }

            public override bool GetPropertiesSupported(ITypeDescriptorContext context)
            {
                return true;
            }

            public override PropertyDescriptorCollection GetProperties(ITypeDescriptorContext context, object value, Attribute[] attributes)
            {
                return TypeDescriptor.GetProperties(typeof(Corners));
            }
        }
    }
}


And finally the code for ButtonControl.cs:

using ASD.Drawing.Enums;
using ASD.Drawing.Properties;
using ASD.Forms.Base;
using ASD.Forms.Interfaces;
using ASD.Global.Helpers;
using System;
using System.ComponentModel;
using System.Drawing;
using System.Windows.Forms;

namespace ASD.Forms.Controls
{
    [ToolboxItem(true)]
    public partial class ButtonControl : BaseControl
    {
        #region Enumerables

        public enum ButtonState
        {
            Normal = 0,
            Pressed = 1
        }

        #endregion Enumerables

        #region Private Members

        private ButtonState _buttonState = ButtonState.Normal;
        private Color _buttonColor = Color.Red;
        private string _caption = String.Empty;

        private Timer _repeatTimer = null;
        private bool _repeatState = false;
        private int _startRepeatInterval = 500;
        private int _repeatInterval = 100;

        //Shape properties
        private ShapenStyle _buttonStyle = ShapenStyle.Rectangular;

        private Corners _corners = new Corners();
        private ShapeOrientation _orientation = ShapeOrientation.Horizontal;

        private void SetPropertyAttributes()
        {
            switch (_buttonStyle)
            {
                case ShapenStyle.Circular:
                case ShapenStyle.Elliptical:
                    PropertyHandler.SetPropertyVisibility(this, "Corners", false);
                    PropertyHandler.SetPropertyVisibility(this, "Orientation", false);
                    break;

                case ShapenStyle.Parallellogram:
                    PropertyHandler.SetPropertyVisibility(this, "Corners", true);
                    PropertyHandler.SetPropertyVisibility(this, "Orientation", true);

                    PropertyHandler.SetPropertyVisibilityByPath(this, "Corners.TopLeft", false);
                    break;

                case ShapenStyle.Rectangular:
                default:
                    PropertyHandler.SetPropertyVisibility(this, "Corners", true);
                    PropertyHandler.SetPropertyVisibility(this, "Orientation", false);

                    PropertyHandler.SetPropertyVisibilityByPath(this, "Corners.TopLeft", true);
                    break;
            }
        }

        private void SetTheCorners(Corners value)
        {
            switch (_buttonStyle)
            {
                case ShapenStyle.Parallellogram:
                    _corners.CopyRadiuses(value);

                    if (_corners.TopRight.Angle != value.TopLeft.Angle)
                    {
                        _corners.BottomRight.Angle = _corners.TopLeft.Angle;
                        _corners.TopRight.Angle = 180 - _corners.TopLeft.Angle;
                        _corners.BottomLeft.Angle = _corners.TopRight.Angle;
                        Caption = "Par: TopLeft";
                    }
                    else if (_corners.TopRight.Angle != value.TopRight.Angle)
                    {
                        _corners.TopLeft.Angle = 180 - _corners.TopRight.Angle;
                        _corners.BottomRight.Angle = _corners.TopLeft.Angle;
                        _corners.BottomLeft.Angle = _corners.TopRight.Angle;
                        Caption = "Par: TopRight";
                    }
                    else if (_corners.BottomRight.Angle != value.BottomRight.Angle)
                    {
                        _corners.TopLeft.Angle = _corners.BottomRight.Angle;
                        _corners.TopRight.Angle = 180 - _corners.TopLeft.Angle;
                        _corners.BottomLeft.Angle = _corners.TopRight.Angle;
                        Caption = "Par: BottomRight";
                    }
                    else
                    {
                        _corners.TopLeft.Angle = 180 - _corners.BottomLeft.Angle;
                        _corners.BottomRight.Angle = _corners.TopLeft.Angle;
                        _corners.TopRight.Angle = _corners.BottomLeft.Angle;
                        Caption = "Par: BottomLeft";
                    }

                    break;

                case ShapenStyle.Rectangular:
                    _corners = value;
                    _corners.ResetAngles();
                    Caption = "Rectangle";
                    break;

                default:
                    _corners = value;
                    break;
            }
        }

        #endregion Private Members

        #region Constructors

        public ButtonControl()
        {
            InitializeComponent();

            //ButtonColor = Color.Red;
            Size = new Size(50, 50);
            SetPropertyAttributes();

            _repeatTimer = new Timer
            {
                Enabled = false,
                Interval = _startRepeatInterval
            };
            _repeatTimer.Tick += OnTimerTick;
        }

        #endregion Constructors

        #region Methods

        protected override IRenderer CreateDefaultRenderer()
        {
            return new Renderers.ButtonRenderer();
        }

        #endregion Methods

        #region Properties

        [RefreshProperties(RefreshProperties.All)]
        [Category("Appearance")]
        [Description("Style of the button")]
        public ShapenStyle Style
        {
            get { return _buttonStyle; }
            set
            {
                _buttonStyle = value;

                CalculateDimensions();

                SetPropertyAttributes();
            }
        }

        [RefreshProperties(RefreshProperties.All)]
        [Browsable(true)]
        //[ReadOnly(false)]
        [Category("Appearance")]
        [Description("Corners of the shape. For regular shapes the topleft angle is the key angle from which most calculations take place.")]
        public Corners Corners
        {
            get { return _corners; }
            set { SetTheCorners(value); Invalidate(); }
        }

        [Browsable(false)]
        [Category("Appearance")]
        [Description("Orientation of the button shape")]
        public ShapeOrientation Orientation
        {
            get { return _orientation; }
            set { _orientation = value; Invalidate(); }
        }

        [Category("Appearance")]
        [Description("Color of the body of the button")]
        public Color ButtonColor
        {
            get { return _buttonColor; }
            set
            {
                _buttonColor = value;
                Invalidate();
            }
        }

        [Category("Appearance")]
        [Description("Caption of the button")]
        public string Caption
        {
            get { return _caption; }
            set
            {
                _caption = value;
                Invalidate();
            }
        }

        [Category("Behavior")]
        [Description("State of the button")]
        public ButtonState State
        {
            get { return _buttonState; }
            set
            {
                _buttonState = value;
                Invalidate();
            }
        }

        [Category("Behavior")]
        [Description("Enable/Disable the repetition of the event if the button is pressed")]
        public bool RepeatState
        {
            get { return _repeatState; }
            set { _repeatState = value; }
        }

        [Category("Behavior")]
        [Description("Interval to wait in ms for start the repetition")]
        public int StartRepeatInterval
        {
            get { return _startRepeatInterval; }
            set { _startRepeatInterval = value; }
        }

        [Category("Behavior")]
        [Description("Interva in ms for the repetition")]
        public int RepeatInterval
        {
            get { return _repeatInterval; }
            set { _repeatInterval = value; }
        }

        [Browsable(false)]
        public override Color BackColor { get => base.BackColor; set => base.BackColor = value; }

        [Browsable(false)]
        public override Image BackgroundImage { get => base.BackgroundImage; set => base.BackgroundImage = value; }

        [Browsable(false)]
        public override ImageLayout BackgroundImageLayout { get => base.BackgroundImageLayout; set => base.BackgroundImageLayout = value; }

        #endregion Properties

        #region Events

        protected override void OnPaint(PaintEventArgs pe)
        {
            // Calling the base class OnPaint
            base.OnPaint(pe);

            if (Style == ShapenStyle.Circular)
            {
                Width = Math.Min(Width, Height);
                Height = Width;
            }
            //PropertyHandler.SetPropertyVisibility(this, "BorderStyle", false);
        }

        private void OnTimerTick(object sender, EventArgs e)
        {
            _repeatTimer.Enabled = false;

            // Update the interval
            if (_repeatTimer.Interval == _startRepeatInterval)
                _repeatTimer.Interval = _repeatInterval;

            // Call the delagate
            ButtonEventArgs ev = new ButtonEventArgs
            {
                State = State
            };
            OnButtonRepeatState(ev);

            _repeatTimer.Enabled = true;
        }

        private void OnMouseDown(object sender, MouseEventArgs e)
        {
            // Change the state
            State = ButtonState.Pressed;
            Invalidate();

            // Call the delagates
            ButtonEventArgs ev = new ButtonEventArgs
            {
                State = State
            };
            OnButtonChangeState(ev);

            // Enable the repeat timer
            if (RepeatState != false)
            {
                _repeatTimer.Interval = StartRepeatInterval;
                _repeatTimer.Enabled = true;
            }
        }

        private void OnMuoseUp(object sender, MouseEventArgs e)
        {
            // Change the state
            State = ButtonState.Normal;
            Invalidate();

            // Call the delagates
            ButtonEventArgs ev = new ButtonEventArgs
            {
                State = State
            };
            OnButtonChangeState(ev);

            // Disable the timer
            _repeatTimer.Enabled = false;
        }

        #endregion Events

        #region Delegate Events

        public event ButtonChangeState ButtonChangeState;

        public event ButtonRepeatState ButtonRepeatState;

        protected virtual void OnButtonChangeState(ButtonEventArgs e)
        {
            ButtonChangeState?.Invoke(this, e);
        }

        protected virtual void OnButtonRepeatState(ButtonEventArgs e)
        {
            ButtonRepeatState?.Invoke(this, e);
        }

        #endregion Delegate Events
    }

    #region Delegates

    public delegate void ButtonChangeState(object sender, ButtonEventArgs e);

    public delegate void ButtonRepeatState(object sender, ButtonEventArgs e);

    #endregion Delegates

    public class ButtonEventArgs : EventArgs
    {
        public ButtonEventArgs()
        {
        }

        public ButtonControl.ButtonState State { get; set; }
    }
}


What I have tried:

I've searched the internet and found some references i.e. suggestions to serialization. I've tried these suggestions, but nothing seems to work.
Posted
Updated 4-Jun-21 8:38am

1 solution

If I copy'n'paste your code into a new UserControl of an existing project, then comment out the unknown stuff, change the base class to UserControl and rebuild, I get no errors:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace Testing
    {
    [ToolboxItem(true)]
    public partial class ButtonControl : UserControl
        {
        #region Enumerables

        public enum ButtonState
            {
            Normal = 0,
            Pressed = 1
            }

        #endregion Enumerables

        #region Private Members

        private ButtonState _buttonState = ButtonState.Normal;
        private Color _buttonColor = Color.Red;
        private string _caption = String.Empty;

        private Timer _repeatTimer = null;
        private bool _repeatState = false;
        private int _startRepeatInterval = 500;
        private int _repeatInterval = 100;

        //Shape properties
        //private ShapenStyle _buttonStyle = ShapenStyle.Rectangular;

        private Corners _corners = new Corners();
        //private ShapeOrientation _orientation = ShapeOrientation.Horizontal;

        private void SetPropertyAttributes()
            {
            //switch (_buttonStyle)
            //    {
            //    case ShapenStyle.Circular:
            //    case ShapenStyle.Elliptical:
            //        PropertyHandler.SetPropertyVisibility(this, "Corners", false);
            //        PropertyHandler.SetPropertyVisibility(this, "Orientation", false);
            //        break;

            //    case ShapenStyle.Parallellogram:
            //        PropertyHandler.SetPropertyVisibility(this, "Corners", true);
            //        PropertyHandler.SetPropertyVisibility(this, "Orientation", true);

            //        PropertyHandler.SetPropertyVisibilityByPath(this, "Corners.TopLeft", false);
            //        break;

            //    case ShapenStyle.Rectangular:
            //    default:
            //        PropertyHandler.SetPropertyVisibility(this, "Corners", true);
            //        PropertyHandler.SetPropertyVisibility(this, "Orientation", false);

            //        PropertyHandler.SetPropertyVisibilityByPath(this, "Corners.TopLeft", true);
            //        break;
            //    }
            }

        private void SetTheCorners(Corners value)
            {
            //switch (_buttonStyle)
            //    {
            //    case ShapenStyle.Parallellogram:
            //        _corners.CopyRadiuses(value);

            //        if (_corners.TopRight.Angle != value.TopLeft.Angle)
            //            {
            //            _corners.BottomRight.Angle = _corners.TopLeft.Angle;
            //            _corners.TopRight.Angle = 180 - _corners.TopLeft.Angle;
            //            _corners.BottomLeft.Angle = _corners.TopRight.Angle;
            //            Caption = "Par: TopLeft";
            //            }
            //        else if (_corners.TopRight.Angle != value.TopRight.Angle)
            //            {
            //            _corners.TopLeft.Angle = 180 - _corners.TopRight.Angle;
            //            _corners.BottomRight.Angle = _corners.TopLeft.Angle;
            //            _corners.BottomLeft.Angle = _corners.TopRight.Angle;
            //            Caption = "Par: TopRight";
            //            }
            //        else if (_corners.BottomRight.Angle != value.BottomRight.Angle)
            //            {
            //            _corners.TopLeft.Angle = _corners.BottomRight.Angle;
            //            _corners.TopRight.Angle = 180 - _corners.TopLeft.Angle;
            //            _corners.BottomLeft.Angle = _corners.TopRight.Angle;
            //            Caption = "Par: BottomRight";
            //            }
            //        else
            //            {
            //            _corners.TopLeft.Angle = 180 - _corners.BottomLeft.Angle;
            //            _corners.BottomRight.Angle = _corners.TopLeft.Angle;
            //            _corners.TopRight.Angle = _corners.BottomLeft.Angle;
            //            Caption = "Par: BottomLeft";
            //            }

            //        break;

            //    case ShapenStyle.Rectangular:
            //        _corners = value;
            //        _corners.ResetAngles();
            //        Caption = "Rectangle";
            //        break;

            //    default:
            //        _corners = value;
            //        break;
            //    }
            }

        #endregion Private Members

        #region Constructors

        public ButtonControl()
            {
            InitializeComponent();

            //ButtonColor = Color.Red;
            Size = new Size(50, 50);
            SetPropertyAttributes();

            _repeatTimer = new Timer
                {
                Enabled = false,
                Interval = _startRepeatInterval
                };
            _repeatTimer.Tick += OnTimerTick;
            }

        #endregion Constructors

        #region Methods

        //protected override IRenderer CreateDefaultRenderer()
        //    {
        //    return new Renderers.ButtonRenderer();
        //    }

        #endregion Methods

        #region Properties

        //[RefreshProperties(RefreshProperties.All)]
        //[Category("Appearance")]
        //[Description("Style of the button")]
        //public ShapenStyle Style
        //    {
        //    get { return _buttonStyle; }
        //    set
        //        {
        //        _buttonStyle = value;

        //        CalculateDimensions();

        //        SetPropertyAttributes();
        //        }
        //    }

        [RefreshProperties(RefreshProperties.All)]
        [Browsable(true)]
        //[ReadOnly(false)]
        [Category("Appearance")]
        [Description("Corners of the shape. For regular shapes the topleft angle is the key angle from which most calculations take place.")]
        public Corners Corners
            {
            get { return _corners; }
            set { SetTheCorners(value); Invalidate(); }
            }

        //[Browsable(false)]
        //[Category("Appearance")]
        //[Description("Orientation of the button shape")]
        //public ShapeOrientation Orientation
        //    {
        //    get { return _orientation; }
        //    set { _orientation = value; Invalidate(); }
        //    }

        [Category("Appearance")]
        [Description("Color of the body of the button")]
        public Color ButtonColor
            {
            get { return _buttonColor; }
            set
                {
                _buttonColor = value;
                Invalidate();
                }
            }

        [Category("Appearance")]
        [Description("Caption of the button")]
        public string Caption
            {
            get { return _caption; }
            set
                {
                _caption = value;
                Invalidate();
                }
            }

        [Category("Behavior")]
        [Description("State of the button")]
        public ButtonState State
            {
            get { return _buttonState; }
            set
                {
                _buttonState = value;
                Invalidate();
                }
            }

        [Category("Behavior")]
        [Description("Enable/Disable the repetition of the event if the button is pressed")]
        public bool RepeatState
            {
            get { return _repeatState; }
            set { _repeatState = value; }
            }

        [Category("Behavior")]
        [Description("Interval to wait in ms for start the repetition")]
        public int StartRepeatInterval
            {
            get { return _startRepeatInterval; }
            set { _startRepeatInterval = value; }
            }

        [Category("Behavior")]
        [Description("Interva in ms for the repetition")]
        public int RepeatInterval
            {
            get { return _repeatInterval; }
            set { _repeatInterval = value; }
            }

        [Browsable(false)]
        public override Color BackColor { get => base.BackColor; set => base.BackColor = value; }

        [Browsable(false)]
        public override Image BackgroundImage { get => base.BackgroundImage; set => base.BackgroundImage = value; }

        [Browsable(false)]
        public override ImageLayout BackgroundImageLayout { get => base.BackgroundImageLayout; set => base.BackgroundImageLayout = value; }

        #endregion Properties

        #region Events

        //protected override void OnPaint(PaintEventArgs pe)
        //    {
        //    // Calling the base class OnPaint
        //    base.OnPaint(pe);

        //    if (Style == ShapenStyle.Circular)
        //        {
        //        Width = Math.Min(Width, Height);
        //        Height = Width;
        //        }
        //    //PropertyHandler.SetPropertyVisibility(this, "BorderStyle", false);
        //    }

        private void OnTimerTick(object sender, EventArgs e)
            {
            _repeatTimer.Enabled = false;

            // Update the interval
            if (_repeatTimer.Interval == _startRepeatInterval)
                _repeatTimer.Interval = _repeatInterval;

            // Call the delagate
            ButtonEventArgs ev = new ButtonEventArgs
                {
                State = State
                };
            OnButtonRepeatState(ev);

            _repeatTimer.Enabled = true;
            }

        private void OnMouseDown(object sender, MouseEventArgs e)
            {
            // Change the state
            State = ButtonState.Pressed;
            Invalidate();

            // Call the delagates
            ButtonEventArgs ev = new ButtonEventArgs
                {
                State = State
                };
            OnButtonChangeState(ev);

            // Enable the repeat timer
            if (RepeatState != false)
                {
                _repeatTimer.Interval = StartRepeatInterval;
                _repeatTimer.Enabled = true;
                }
            }

        private void OnMuoseUp(object sender, MouseEventArgs e)
            {
            // Change the state
            State = ButtonState.Normal;
            Invalidate();

            // Call the delagates
            ButtonEventArgs ev = new ButtonEventArgs
                {
                State = State
                };
            OnButtonChangeState(ev);

            // Disable the timer
            _repeatTimer.Enabled = false;
            }

        #endregion Events

        #region Delegate Events

        public event ButtonChangeState ButtonChangeState;

        public event ButtonRepeatState ButtonRepeatState;

        protected virtual void OnButtonChangeState(ButtonEventArgs e)
            {
            ButtonChangeState?.Invoke(this, e);
            }

        protected virtual void OnButtonRepeatState(ButtonEventArgs e)
            {
            ButtonRepeatState?.Invoke(this, e);
            }

        #endregion Delegate Events
        }

    #region Delegates

    public delegate void ButtonChangeState(object sender, ButtonEventArgs e);

    public delegate void ButtonRepeatState(object sender, ButtonEventArgs e);

    #endregion Delegates

    public class ButtonEventArgs : EventArgs
        {
        public ButtonEventArgs()
            {
            }

        public ButtonControl.ButtonState State { get; set; }
        }
    [TypeConverter(typeof(Converter))]
    public class Corners
        {
        #region Private Members
        private Corner _topLeft = new Corner();
        private Corner _topRight = new Corner();
        private Corner _bottomLeft = new Corner();
        private Corner _bottomRight = new Corner();

        private Corner GetCornerFromString(string cornerString)
            {
            var cornerArray = cornerString.Trim().Replace("[", "").Replace("]", "").Split(':');

            if (cornerArray.Length >= 2)
                {
                if (int.TryParse(cornerArray[0], out int angle) && int.TryParse(cornerArray[1], out int radius))
                    {
                    return new Corner(angle, radius);
                    }
                }
            throw new FormatException();
            }

        private bool ShouldSerializeTopLeft()
            {
            return _topLeft != new Corner();
            }

        private void ResetTopLeft()
            {
            TopLeft = new Corner();
            }

        private bool ShouldSerializeTopRight()
            {
            return _topRight != new Corner();
            }

        private void ResetTopRight()
            {
            TopRight = new Corner();
            }

        private bool ShouldSerializeBottomRight()
            {
            return _bottomRight != new Corner();
            }

        private void ResetBottomRight()
            {
            BottomRight = new Corner();
            }

        private bool ShouldSerializeBottomLeft()
            {
            return _bottomLeft != new Corner();
            }

        private void ResetBottomLeft()
            {
            BottomLeft = new Corner();
            }

        #endregion Private Members

        #region Constructors

        public Corners()
            {
            TopLeft = new Corner();
            TopRight = new Corner();
            BottomLeft = new Corner();
            BottomRight = new Corner();
            }

        public Corners(Corner topLeft, Corner topRight, Corner bottomRight, Corner bottomLeft)
            {
            TopLeft = topLeft;
            TopRight = topRight;
            BottomLeft = bottomRight;
            BottomRight = bottomLeft;
            }

        public Corners(string allCornersText)
            {
            string[] cornerTextArray = allCornersText.Split(':');
            if (cornerTextArray.Length >= 4)
                {
                Corner[] corners = new Corner[4];

                for (int i = 0; i < 4; i++) { corners[i] = GetCornerFromString(cornerTextArray[i]); }

                TopLeft = corners[0];
                TopRight = corners[1];
                BottomLeft = corners[2];
                BottomRight = corners[3];
                }
            else
                {
                throw new FormatException();
                }
            }

        public Corners(string topLeft, string topRight, string bottomRight, string bottomLeft)
            {
            TopLeft = GetCornerFromString(topLeft);
            TopRight = GetCornerFromString(topRight);
            BottomLeft = GetCornerFromString(bottomRight);
            BottomRight = GetCornerFromString(bottomLeft);
            }

        #endregion Constructors

        #region Properties

        [Browsable(true)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        [RefreshProperties(RefreshProperties.Repaint)]
        [NotifyParentProperty(true)]
        [Description("Border settings for top left corner")]
        public Corner TopLeft
            {
            get { return _topLeft; }
            set { _topLeft = value; }
            }

        //[Browsable(true)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        [RefreshProperties(RefreshProperties.Repaint)]
        [NotifyParentProperty(true)]
        [Description("Border settings for top right corner")]
        public Corner TopRight
            {
            get { return _topRight; }
            set { _topRight = value; }
            }

        //[Browsable(true)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        [RefreshProperties(RefreshProperties.Repaint)]
        [NotifyParentProperty(true)]
        [Description("Border settings for bottom right corner")]
        public Corner BottomRight
            {
            get { return _bottomRight; }
            set { _bottomRight = value; }
            }

        //[Browsable(true)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        [RefreshProperties(RefreshProperties.Repaint)]
        [NotifyParentProperty(true)]
        [Description("Border settings for bottom left corner")]
        public Corner BottomLeft
            {
            get { return _bottomLeft; }
            set { _bottomLeft = value; }
            }

        #endregion Properties

        #region Methods
        public void CopyAngles(Corners source)
            {
            _topLeft.Angle = source.TopLeft.Angle;
            _topRight.Angle = source.TopRight.Angle;
            _bottomLeft.Angle = source.BottomLeft.Angle;
            _bottomRight.Angle = source.BottomRight.Angle;
            }

        public void CopyRadiuses(Corners source)
            {
            _topLeft.Radius = source.TopLeft.Radius;
            _topRight.Radius = source.TopRight.Radius;
            _bottomLeft.Radius = source.BottomLeft.Radius;
            _bottomRight.Radius = source.BottomRight.Radius;
            }

        public void ResetAngles()
            {
            _topLeft.Angle = 90;
            _topRight.Angle = 90;
            _bottomLeft.Angle = 90;
            _bottomRight.Angle = 90;
            }

        public void ResetCorners()
            {
            _topLeft = new Corner();
            _topRight = new Corner();
            _bottomLeft = new Corner();
            _bottomRight = new Corner();
            }

        public void ResetRadiuses()
            {
            _topLeft.Radius = 0;
            _topRight.Radius = 0;
            _bottomLeft.Radius = 0;
            _bottomRight.Radius = 0;
            }

        public bool ValidAngles()
            {
            return (_topLeft.Angle + _topRight.Angle + _bottomLeft.Angle + _bottomRight.Angle) == 360;
            }

        public override string ToString()
            {
            return $"{TopLeft.ToString().Trim()};{TopRight.ToString().Trim()};{BottomLeft.ToString().Trim()};{BottomRight.ToString().Trim()}";
            }

        #endregion Methods

        public partial class Converter : ExpandableObjectConverter
            {
            public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
                {
                if (ReferenceEquals(sourceType, typeof(string)))
                    {
                    return true;
                    }
                // Allow conversion from string
                return base.CanConvertFrom(context, sourceType);
                }

            public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
                {
                if (ReferenceEquals(value.GetType(), typeof(string)))
                    {
                    // Conversion from string
                    var stringArray = value.ToString().Split(';');
                    bool isValid = true;
                    string message = string.Empty;

                    if (stringArray.Length >= 4)
                        {
                        Corner[] corners = new Corner[4];
                        for (int i = 0; i < 4 && isValid; i++)
                            {
                            //var cornerString = stringArray[i].Replace("[", "").Replace("]", "").Split(':');
                            var cornerString = stringArray[i].Split(':');
                            if (int.TryParse(cornerString[0], out int angle) && int.TryParse(cornerString[1], out int radius))
                                {
                                corners[i] = new Corner(angle, radius);
                                }
                            else
                                {
                                isValid = false;
                                message = "Parsing of the corner[" + i.ToString() + "] failed!";
                                }
                            }

                        if (isValid) return new Corners(corners[0], corners[1], corners[2], corners[3]);
                        }
                    else message = "Not enough parameters in string value, or wrong separator used in splitting the value!";

                    throw new FormatException(message);
                    }

                return base.ConvertFrom(context, culture, value);
                }

            public override bool GetCreateInstanceSupported(ITypeDescriptorContext context)
                {
                //Alway force a new instance
                return true;

                //Original default statement
                //return base.GetCreateInstanceSupported(context);
                }

            //public override object CreateInstance(ITypeDescriptorContext context, IDictionary propertyValues)
            //    {
            //    //Use the dictionary to create a new instance
            //    //return new Corners((Corner)propertyValues["TopLeft"], (Corner)propertyValues["TopRight"], (Corner)propertyValues["BottomRight"], (Corner)propertyValues["BottomLeft"]);

            //    //Original default statement
            //    return base.CreateInstance(context, propertyValues);
            //    }

            public override bool GetPropertiesSupported(ITypeDescriptorContext context)
                {
                return true;
                }

            public override PropertyDescriptorCollection GetProperties(ITypeDescriptorContext context, object value, Attribute[] attributes)
                {
                return TypeDescriptor.GetProperties(typeof(Corners));
                }
            }
        }
    [TypeConverter(typeof(CornerConverter))]
    public class Corner : IEquatable<Corner>
        {
        #region Private Members

        private const int DEFAULT_ANGLE = 90;
        private const int DEFAULT_RADIUS = 0;

        private int _angle = DEFAULT_ANGLE;
        private int _radius = DEFAULT_RADIUS;

        private bool ShouldSerializeAngle()
            {
            return _angle != DEFAULT_ANGLE;
            }

        private void ResetAngle()
            {
            Angle = DEFAULT_ANGLE;
            }

        private bool ShouldSerializeRadius()
            {
            return _radius != DEFAULT_RADIUS;
            }

        private void ResetRadius()
            {
            Radius = DEFAULT_RADIUS;
            }

        #endregion Private Members

        #region Constructors

        public Corner()
            {
            Angle = DEFAULT_RADIUS;
            Radius = 0;
            }

        public Corner(int angle, int radius)
            {
            Angle = angle > 0 ? angle : DEFAULT_RADIUS;
            Radius = radius > 0 ? radius : 0;
            }

        #endregion Constructors

        #region Properties

        [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
        [RefreshProperties(RefreshProperties.Repaint)]
        [NotifyParentProperty(true)]
        //[DefaultValue(90)]
        [Description("Angle of the corner.")]
        public int Angle
            {
            get { return _angle; }
            set { _angle = value; }
            }

        [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
        [RefreshProperties(RefreshProperties.Repaint)]
        [NotifyParentProperty(true)]
        //[DefaultValue(0)]
        [Description("Radius of the corner")]
        public int Radius
            {
            get { return _radius; }
            set { _radius = value; }
            }

        #endregion Properties

        #region Methods

        public override bool Equals(object obj) => this.Equals(obj as Corner);

        public bool Equals(Corner p)
            {
            if (p is null)
                {
                return false;
                }

            // Optimization for a common success case.
            if (Object.ReferenceEquals(this, p))
                {
                return true;
                }

            // If run-time types are not exactly the same, return false.
            if (this.GetType() != p.GetType())
                {
                return false;
                }

            // Return true if the fields match.
            // Note that the base class is not invoked because it is
            // System.Object, which defines Equals as reference equality.
            return (Angle == p.Angle) && (Radius == p.Radius);
            }

        public override int GetHashCode() => (Angle, Radius).GetHashCode();

        public static bool operator ==(Corner lhs, Corner rhs)
            {
            if (lhs is null)
                {
                if (rhs is null)
                    {
                    return true;
                    }

                // Only the left side is null.
                return false;
                }
            // Equals handles case of null on right side.
            return lhs.Equals(rhs);
            }

        public static bool operator !=(Corner lhs, Corner rhs) => !(lhs == rhs);

        public override string ToString()
            {
            return $"[{Angle.ToString().Trim()}:{Radius.ToString().Trim()}]";
            }

        #endregion Methods

        public partial class CornerConverter : ExpandableObjectConverter
            {
            public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
                {
                if (ReferenceEquals(sourceType, typeof(string)))
                    {
                    return true;
                    }
                // Allow conversion from string
                return base.CanConvertFrom(context, sourceType);
                }

            public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
                {
                if (ReferenceEquals(value.GetType(), typeof(string)))
                    {
                    // Conversion from
                    var stringArray = value.ToString().Replace("[", "").Replace("]", "").Split(':');
                    //var stringArray = value.ToString().Split(':');

                    if (stringArray.Length >= 2)
                        {
                        if (int.TryParse(stringArray[0], out int angle) && int.TryParse(stringArray[1], out int radius))
                            {
                            return new Corner(angle, radius);
                            }
                        }

                    throw new FormatException();
                    }

                return base.ConvertFrom(context, culture, value);
                }

            // Overrides the ConvertTo method of TypeConverter.
            public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType)
                {
                if (destinationType == typeof(string))
                    {
                    //return ((Corner)value).Angle + ":" + ((Corner)value).Radius;
                    return $"[{((Corner)value).Angle}:{((Corner)value).Radius}]";
                    }
                return base.ConvertTo(context, culture, value, destinationType);
                }

            public override bool GetCreateInstanceSupported(ITypeDescriptorContext context)
                {
                //Alway force a new instance
                return true;

                //Original default statement
                //return base.GetCreateInstanceSupported(context);
                }

            //public override object CreateInstance(ITypeDescriptorContext context, IDictionary propertyValues)
            //    {
            //    //Use the dictionary to create a new instance
            //    return new Corner((int)propertyValues["Angle"], (int)propertyValues["Radius"]);

            //    //Original default statement
            //    //return base.CreateInstance(context, propertyValues);
            //    }

            public override bool GetPropertiesSupported(ITypeDescriptorContext context)
                {
                return true;
                }

            public override PropertyDescriptorCollection GetProperties(ITypeDescriptorContext context, object value, Attribute[] attributes)
                {
                return TypeDescriptor.GetProperties(typeof(Corner));
                }
            }
        }
    }
So ... I'd guess it's caused elsewhere than in that code.

My best guess would be that you have multiple projects, and it's to do with the order in which they are compiled: if ProjectA references ProjectB but is compiled first then changes from ProjectB wouldn't be included - and that can cause some strange results when the designer tries to use controls afterwards.

I'd start by doing a full clean and rebuild all to see if that helps - sometimes my modification dates seemed to get a little odd with VS2015, but it hasn't happened to me for quite a while now...
 
Share this answer
 
Comments
Member 11728887 5-Jun-21 4:37am    
A full clean and rebuild doesn't work. Once the message is shown in the properties window it doesn't disappear anymore. Not even by unloading and reloading the projects and clean and rebuild them. Only when Visual Studio is restarted the message is gone.
OriginalGriff 5-Jun-21 4:45am    
You're probably going to have to talk to MS tech support - they do know their stuff, and they can dive into your computer to fix it.
Member 11728887 6-Jun-21 7:17am    
Thanks for your effort. I will contact MS and in the meantime I will carry on searching and investigating.
OriginalGriff 6-Jun-21 7:56am    
You're welcome!
Good luck.

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



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900