Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Implementing TypeConverter for Windows Forms

Tags:

c#

winforms

I want to implement TypeConverter for a custom type, Thickness. I've looked over the microsoft released typeconverters like SizeConverter.

When I type a string or change one of the properties on my Thickness property, the designer works with it, it just doesn't save the change to 'Designer.cs'. It has to be the conversion from the type 'Thickness' to 'InstanceDescriptor' but I can't find anything wrong with my code...

Here is Thickness:

[TypeConverter(typeof(ThicknessConverter))]
public struct Thickness
{
    Double top;
    Double bottom;
    Double right;
    Double left;

    public Thickness(Double uniformLength)
    {
        top = uniformLength;
        bottom = uniformLength;
        right = uniformLength;
        left = uniformLength;
    }

    public Thickness(Double left, Double top, Double right, Double bottom)
    {
        this.left = left;
        this.top = top;
        this.right = right;
        this.bottom = bottom;
    }
    public Double Top
    {
        get { return top; }
        set { top = value; }
    }
    public Double Bottom
    {
        get { return bottom; }
        set { bottom = value; }
    }
    public Double Right
    {
        get { return right; }
        set { right = value; }
    }
    public Double Left
    {
        get { return left; }
        set { left = value; }
    }
    public Double UniformLength
    {
        get
        {
            if (!IsUniform)
                throw new InvalidOperationException();
            else return top;
        }
        set
        {
            top = value;
            bottom = value;
            right = value;
            bottom = value;
        }
    }
    public Boolean IsUniform
    {
        get { return top == bottom && bottom == right && bottom == left; }
    }
}

And here is the type converter:

public class ThicknessConverter : TypeConverter
{
    public ThicknessConverter()
    {
    }

    public override Boolean CanConvertTo(ITypeDescriptorContext context, Type destinationType)
    {
        return destinationType == typeof(String) || destinationType == typeof(InstanceDescriptor);
    }
    public override Object ConvertTo(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, Object value, Type destinationType)
    {
        Thickness thickness = (Thickness)value;
        if (destinationType == typeof(String))
        {
            if (thickness.IsUniform)
                return thickness.Right.ToString();
            else return thickness.Left + "," + thickness.Top + "," + thickness.Right + "," + thickness.Bottom;
        }
        else if (destinationType == typeof(InstanceDescriptor))
        {
            if (thickness.IsUniform)
                return new InstanceDescriptor(typeof(Thickness).GetConstructor(new Type[] { typeof(Double) }), new Object[] { thickness.UniformLength });
            else
            {
                ConstructorInfo constructor = typeof(Thickness).GetConstructor(new Type[] { typeof(Double), typeof(Double), typeof(Double), typeof(Double) });
                return new InstanceDescriptor(constructor, new Object[] { thickness.Left, thickness.Top, thickness.Right, thickness.Bottom });
            }
        }
        else return null;
    }
    public override Boolean CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
    {
        return sourceType == typeof(String);
    }
    public override Object ConvertFrom(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, Object value)
    {
        if (value is String)
        {
            String stringValue = (String)value;
            if (stringValue.Contains(","))
            {
                String[] stringValues = stringValue.Split(',');
                Double[] values = new Double[stringValues.Length];
                if (values.Length == 4)
                {
                    try
                    {
                        for (Int32 i = 0; i < 4; i++)
                            values[i] = Double.Parse(stringValues[i]);
                    }
                    catch (Exception)
                    {
                        return new Thickness();
                    }
                    return new Thickness(values[0], values[1], values[2], values[3]);
                }
                else return new Thickness();
            }
            else
            {
                try
                {
                    return new Thickness(Double.Parse(stringValue));
                }
                catch (Exception)
                {
                    return new Thickness();
                }
            }
        }
        else return base.ConvertFrom(context, culture, value);
    }
    public override Boolean GetCreateInstanceSupported(ITypeDescriptorContext context)
    {
        return true;
    }
    public override Object CreateInstance(ITypeDescriptorContext context, System.Collections.IDictionary propertyValues)
    {
        return new Thickness((Double)propertyValues["Left"], (Double)propertyValues["Top"], (Double)propertyValues["Right"], (Double)propertyValues["Bottom"]);
    }

    public override Boolean GetPropertiesSupported(ITypeDescriptorContext context)
    {
        return true;
    }
    public override PropertyDescriptorCollection GetProperties(ITypeDescriptorContext context, Object value, Attribute[] attributes)
    {
        PropertyDescriptorCollection collection = TypeDescriptor.GetProperties(typeof(Thickness));
        collection = collection.Sort(new String[] { "Left", "Top", "Right", "Bottom" });
        collection.RemoveAt(4);
        collection.RemoveAt(4);
        return collection;
    }
}

The only thing I can think of is does the converter have to be in a seperate assembly than the designer code using it?

like image 442
Ryan Brown Avatar asked Nov 13 '13 22:11

Ryan Brown


People also ask

Does Microsoft still support WinForms?

"We continue to support and innovate in Windows Forms runtime," said Microsoft's Igor Velikorossov last month in announcing what's new for WinForms in . NET 6. He's a software engineer on the dev team for the 19-year-old product, a free and open-source graphical (GUI) class library included as a part of .

Are WinForms deprecated?

WinForms won't be deprecated until Win32 is ... which could be quite sometime! WPF on the other hand has few direct dependencies on Win32 so could potentially form the basis of a "fresh start" UI layer on a future version of windows.

How do I organize Windows Forms?

In Microsoft Forms, scroll down to the bottom of your page and select All My Forms. On the All forms tab, select New Collection. Provide a name for your collection and select Create. Your new collection will appear as a tile in the first spot of the top row of your forms.

What is Typeconverter C#?

Provides a unified way of converting types of values to other types, as well as for accessing standard values and subproperties.


2 Answers

So, I hope that my investigation was ended succesfully.

The result:
This is something strange. It seems there is some bug in VS2008.
To get your code works as expected:
1. Rename ThicknessConverter to something else (for example: Thickness1Converter).
2. Build the solution by pressing Shift+F6.

Now you should be able to edit the Thickness property in the designer UI. The appropriate code will appear in the *.Designer.cs file.

After that, in some circumstances, it is possible to rename it back to the ThicknessConverter without getting an error. But I can't discover the rule, sorry.

If something isn't clear enough, do not hesitate to ask me.

Good luck.

like image 171
Dmitry Avatar answered Oct 05 '22 07:10

Dmitry


This works fine for me. Here are the steps I followed:

  1. Start VS2010.
  2. Create a new WinForms project (.NET Framework 4 Client Profile).
  3. Copy-paste your Thickness and ThicknessConverter classes.
  4. Create a new user control UserControl1.
  5. Add a property to the user control: public Thickness Thickness { get; set; }
  6. Build project.
  7. Open Form1 designer.
  8. Place a UserControl1 on Form1.
  9. Select UserControl1.
  10. Edit Thickness property.
  11. Save.
  12. Verify thickness is correct in Form1.Designer.cs.

If this isn't working for you, you're either doing something else in your project, or there is a difference in our setups. Can you provide details (.NET version, for example)?

like image 42
Michael Gunter Avatar answered Oct 05 '22 06:10

Michael Gunter