I'm making controls for my winform program, and this error happens when saving the test form.
This is the solution structure, the controls library is seperated in 1 project and another is a test project contains a test form.
Solution
├ Test (Test Project)
│ └ Form1
└ WinFormControls (Library Project)
└ ImageButton (UserControl)
The control has a TypeConverter
attached, here is brief code.
To make the question simple, I omit other methods, you can read it from this link
public class StateConverter : ExpandableObjectConverter
{
public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType)
{
if(destinationType == typeof(InstanceDescriptor))
{
var ctor = typeof(State).GetConstructor(new Type[] { typeof(int), typeof(Image) });
if (ctor != null)
{
var state = (State)value;
return new InstanceDescriptor(ctor, new object[] { state.GetData(), state.Image });
}
}
return base.ConvertTo(context, culture, value, destinationType);
}
}
The error is not always happens here are steps to reproduce:
After some debug, I found the error occurs with this line:
var state = (State)value;
At first I guessed the value is null, so I added some log with it:
try {
var state = (State)value;
} catch (Exception ex) {
File.AppendAllText("errorlog.txt", ex.ToString() +
(value == null ? "NULL" : value.GetType().ToString());
}
Finally I got:
System.InvalidCastException: Specified cast is not valid. at WinFormControls.ImageButton.StateConverter.ConvertTo ...... WinFormControls.ImageButton+State
So the value is not null, and the type of value is exactly what I cast to.
Update
Output AssemblyQualifiedName, IsAssignableFrom, is:
value.GetType().AssemblyQualifiedName;
typeof(State).AssemblyQualifiedName;
typeof(State).IsAssignableFrom(value.GetType());
value.GetType().IsAssignableFrom(typeof(State))
value is State
ReferenceEquals(value.GetType(), typeof(State))
Strange result:
WinFormControls.ImageButton+State, WinFormControls, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
WinFormControls.ImageButton+State, WinFormControls, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
False
False
False
False
Two questions:
This is because of the different way that type converter and designer loads the type. Type converter uses CLR cache to load the type while designer uses type resolutions service. So when you change the class library project and build it again, the CLR loads the assembly from previously cached version of the type in CLR, while designer loads it from newly built assembly and it results in a type mismatch.
To solve the problem, in the class library project:
Open AssemblyInfo.CS
and change assembly version attribute to change the build number of the assembly in each build and save the file. This forces the CLR to invalidate its cache and load the new type from the new version of assembly:
[assembly: AssemblyVersion("1.0.0.*")]
Right click and unload the class library project, then right click and edit the project file and change the project deterministic build to false:
<Deterministic>false</Deterministic>
The problem is already addressed in this forum post.