Search code examples
.netwinformsuser-controlscustom-controlsdesigner

How to add designer support for Point property on custom control?


I have a custom control with a property called Offset that is type PointF.

I want to be able to edit the property from the Form Designer (it is currently disabled).

I read that I must add the EditorAttribute which points to a class derived from System.Drawing.Design.UITypeEditor.

It looks like there are quite a few built in types that derive from UITypeEditor already such as:

System.ComponentModel.Design.BinaryEditor
System.ComponentModel.Design.CollectionEditor
System.ComponentModel.Design.DateTimeEditor
System.ComponentModel.Design.MultilineStringEditor
System.ComponentModel.Design.ObjectSelectorEditor
System.Drawing.Design.ColorEditor
System.Drawing.Design.ContentAlignmentEditor
System.Drawing.Design.CursorEditor
System.Drawing.Design.FontEditor
System.Drawing.Design.FontNameEditor
System.Drawing.Design.IconEditor

... etc

I can't find one for editing a PointF or Point type. It seems like this functionality should already exist since .NET exposes Point/PointF types all the time in the designer.

I'm hoping I don't have to reinvent the wheel - I want to use the built in UITypeEditor type if it already exists.

Thanks.


Solution

  • You can add a property to a custom control of type Point that allows editing in the control's property grid using this code:

    [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible),
     EditorBrowsable(EditorBrowsableState.Advanced),
     TypeConverter(typeof(PointConverter))]
    public Point MyPointProperty { get; set; }
    

    If you try the same sort of approach with a SizeF you'll find there's no built in .NET TypeConverter for a PointF. You can create your own though, I found one here (and copy and pasted most of the code below).

    With a PointF TypeConverter you can write a property of type PointF that's editable in the property window:

    [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible),
     EditorBrowsable(EditorBrowsableState.Advanced),
     TypeConverter(typeof(PointFConverter))]
    public PointF MyPointFProperty { get; set; }
    

    Here's the PointF type converter code found in the article linked above:

    /// <summary>
    /// PointFConverter
    /// </summary>
    public class PointFConverter : ExpandableObjectConverter
    {
        /// <summary>
        /// Creates a new instance of PointFConverter
        /// </summary>
        public PointFConverter() {
        }
    
        /// <summary>
        /// Boolean, true if the source type is a string
        /// </summary>
        public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType) {
            if (sourceType == typeof(string)) return true;
            return base.CanConvertFrom(context, sourceType);
        }
    
        /// <summary>
        /// Converts the specified string into a PointF
        /// </summary>
        public override object ConvertFrom(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value) {
            if (value is string) {
                try {
                    string s = (string)value;
                    string[] converterParts = s.Split(',');
                    float x = 0;
                    float y = 0;
                    if (converterParts.Length > 1) {
                        x = float.Parse(converterParts[0].Trim());
                        y = float.Parse(converterParts[1].Trim());
                    } else if (converterParts.Length == 1) {
                        x = float.Parse(converterParts[0].Trim());
                        y = 0;
                    } else {
                        x = 0F;
                        y = 0F;
                    }
                    return new PointF(x, y);
                } catch {
                    throw new ArgumentException("Cannot convert [" + value.ToString() + "] to pointF");
                }
            }
            return base.ConvertFrom(context, culture, value);
        }
    
        /// <summary>
        /// Converts the PointF into a string
        /// </summary>
        public override object ConvertTo(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, Type destinationType) {
            if (destinationType == typeof(string)) {
                if (value.GetType() == typeof(PointF)) {
                    PointF pt = (PointF)value;
                    return string.Format("{0}, {1}", pt.X, pt.Y);
                }
            }
            return base.ConvertTo(context, culture, value, destinationType);
        }
    }