Hi,
I am experiencing some weird problems with Visual Studio 2005's Property
Grid in the designer, whenever I rebuild my assemblies containing my custom
TypeConverters. It seems to me that the Property Grid doesn't reload the
rebuilded assembly.
I have created a class called CornerType with a CornerTypeConverter, the
CornerTypeConverter creates a new instance of CornerType, whenever one of
CornerType values are changed - very simular to System.Windows.Forms.Padding
and System.Windows.Forms.PaddingConverter.
At times the CornerTypeConverter will need to cast an object (of type
CornerType) to CornerType. This works fine right until I build a new version
of the assembly (dll) that contains the CornerType and CornerTypeConverter.
After that I get an castexception, when trying to cast an object (of type
CornerType) to CornerType. It seems, that the object I am casting from is a
different version of CornerType than the CornerType I am trying to cast to.
It is very simple to reproduce:
1. Just make a simple WinForm application (C#), add the code for CornerType
and CornerTypeConverter (posted below), add a UserControl with a CorneType
property and BUILD your solution.
2. Add the UserControl to your Form.
3. In the designer, You can change the value of the CornerType, either by
expanding the property and modify a field, or by entering a string in the
'header'.
The string should be a single number or 4 numbers seperated by a ';' or ','.
4. REBUILD the solution.
5. now if you repeat step 3 you will get various cast exceptions.
When changing the property by entering a string, you will invoke the
ConvertFrom() in the CornerTypeConverter which will throw following
exception:
Object of type 'Oticon.Genie.Forms.CornersType' cannot be converted to type
'Oticon.Genie.Forms.CornersType'.
When changing the property by expanding it, and modifying a field, you will
invoke the CreateInstance() in the CornerTypeConverter which will throw
following exception:
Specified cast is not valid.
6. Now close and reopen Visual Studio, and repeat step 3, now it works fine
again!!!
Included code for CornersType.cs and CornersTypeConverter.cs
CornersType.cs:
using System;
using System.Collections.Generic;
using System.Text;
using System.ComponentModel;
using System.Runtime.InteropServices;
namespace CornerTypeTest
{
[TypeConverter(typeof(CornersTypeConverter))]
public struct CornersType
{
public const int defaultRadius = 10;
public const string defaultCornerTypeStr = "10; 10; 10; 10";
[DefaultValue(defaultRadius)]
[RefreshProperties(RefreshProperties.All)]
public int All
{
get
{
if (topRight == topLeft && bottomLeft == topLeft &&
bottomRight == topLeft)
return topLeft;
return -1;
}
set
{
topLeft = value; topRight = value; bottomLeft = value;
bottomRight = value;
}
}
private int topLeft;
[DefaultValue(defaultRadius)]
[RefreshProperties(RefreshProperties.All)]
public int TopLeft
{
get { return topLeft; }
set
{
topLeft = value;
}
}
private int topRight;
[DefaultValue(defaultRadius)]
[RefreshProperties(RefreshProperties.All)]
public int TopRight
{
get { return topRight; }
set
{
topRight = value;
}
}
private int bottomLeft;
[DefaultValue(defaultRadius)]
[RefreshProperties(RefreshProperties.All)]
public int BottomLeft
{
get { return bottomLeft; }
set
{
bottomLeft = value;
}
}
private int bottomRight;
[DefaultValue(defaultRadius)]
[RefreshProperties(RefreshProperties.All)]
public int BottomRight
{
get { return bottomRight; }
set
{
bottomRight = value;
}
}
//public CornersType()
//{
// this.topLeft = defaultRadius;
// this.topRight = defaultRadius;
// this.bottomLeft = defaultRadius;
// this.bottomRight = defaultRadius;
//}
public CornersType(int all)
{
this.topLeft = all;
this.topRight = all;
this.bottomLeft = all;
this.bottomRight = all;
}
public CornersType(int topLeft, int topRight, int bottomLeft, int
bottomRight)
{
this.topLeft = topLeft;
this.topRight = topRight;
this.bottomLeft = bottomLeft;
this.bottomRight = bottomRight;
}
public static bool operator ==(CornersType ct1, CornersType ct2)
{
return ((ct1.topLeft == ct2.topLeft) && (ct1.topRight ==
ct2.topRight) && (ct1.bottomLeft == ct2.bottomLeft) && (ct1.bottomRight ==
ct2.bottomRight));
}
public static bool operator !=(CornersType ct1, CornersType ct2)
{
return !(ct1 == ct2);
}
public override bool Equals(object obj)
{
if (obj is CornersType)
return (CornersType)obj == this;
return false;
}
public override int GetHashCode()
{
return base.GetHashCode();
}
}
}
CornersTypeConverter.cs:
using System;
using System.Collections.Generic;
using System.Text;
using System.ComponentModel;
using System.Globalization;
using System.Drawing;
using System.Collections;
using System.ComponentModel.Design.Serialization;
using System.Windows.Forms;
namespace CornerTypeTest
{
class CornersTypeConverter : TypeConverter
{
public override bool GetPropertiesSupported(ITypeDescriptorContext
context)
{
return true;
}
public override PropertyDescriptorCollection
GetProperties(ITypeDescriptorContext context, object value, Attribute[]
attributes)
{
PropertyDescriptorCollection properties =
TypeDescriptor.GetProperties(value, attributes);
return properties.Sort(new string[] { "All", "TopLeft",
"TopRight", "BottomLeft", "BottomRight" });
}
public override bool CanConvertTo(ITypeDescriptorContext context,
Type destinationType)
{
if (destinationType == typeof(InstanceDescriptor))
return true;
if (destinationType == typeof(String))
return true;
return base.CanConvertTo(context, destinationType);
}
public override object ConvertTo(ITypeDescriptorContext context,
System.Globalization.CultureInfo culture, object value, Type destinationType)
{
if (destinationType == typeof(String))
{
CornersType corners = (CornersType)value;
return string.Format("{0}; {1}; {2}; {3}", corners.TopLeft,
corners.TopRight, corners.BottomLeft, corners.BottomRight);
}
if (destinationType == typeof(InstanceDescriptor))
{
CornersType corners = (CornersType)value;
if (corners.All != -1)
return new
InstanceDescriptor(typeof(CornersType).GetConstructor(new Type[] {
typeof(int) }), new object[] { corners.All });
return new
InstanceDescriptor(typeof(CornersType).GetConstructor(new Type[] {
typeof(int), typeof(int), typeof(int), typeof(int) }), new object[] {
corners.TopLeft, corners.TopRight, corners.BottomLeft, corners.BottomRight });
}
return base.ConvertTo(context, culture, value, destinationType);
}
public override bool CanConvertFrom(ITypeDescriptorContext context,
Type sourceType)
{
if (sourceType == typeof(string))
return true;
return base.CanConvertFrom(context, sourceType);
}
public override object ConvertFrom(ITypeDescriptorContext context,
System.Globalization.CultureInfo culture, object value)
{
if (value is string)
{
string[] values;
//first try with ';' as delimiter
if (((string)value).Contains(";"))
values = ((string)value).Split(new char[] { ';' });
//if no success then try with ',' as delimiter
else
values = ((string)value).Split(new char[] { ',' });
if (values.Length == 4)
return new CornersType(int.Parse(values[0]),
int.Parse(values[1]), int.Parse(values[2]), int.Parse(values[3]));
else if (values.Length == 1)
return new CornersType(int.Parse(values[0]));
}
return base.ConvertFrom(context, culture, value);
}
public override bool
GetCreateInstanceSupported(ITypeDescriptorContext context)
{
return true;
}
public override object CreateInstance(ITypeDescriptorContext
context, IDictionary propertyValues)
{
if (context == null)
{
throw new ArgumentNullException("context");
}
if (propertyValues == null)
{
throw new ArgumentNullException("propertyValues");
}
CornersType oldCorners =
(CornersType)context.PropertyDescriptor.GetValue(context.Instance);
int newAll = (int)propertyValues["All"];
if (oldCorners.All != newAll)
{
return new CornersType(newAll);
}
return new CornersType((int)propertyValues["TopLeft"],
(int)propertyValues["TopRight"], (int)propertyValues["BottomLeft"],
(int)propertyValues["BottomRight"]);
}
}
}
Thomas Pagh - 21 Jun 2006 21:39 GMT
I found a solution to thr problem myself.
I just needed to change the AssemblyVersion each time I rebuild the assembly
containing the typeconverter.
One way to do this was to change the AssemblyVersion attribute in the
AssemblyI nfo.cs file to 1.0.0.*.
/Thomas Pagh
> Hi,
>
[quoted text clipped - 296 lines]
> {
> return new CornersType(newAll);