I have a custom c# type like (just an example):
public class MyVector
{
public double X {get; set;}
public double Y {get; set;}
public double Z {get; set;}
//...
}
And I want it to databind to TextBox.Text:
TextBox textBox;
public MyVector MyVectorProperty { get; set;}
//...
textBox.DataBindings.Add("Text", this, "MyVectorProperty");
Essentially I need conversion to and from a string for my custom value type. In the text box, I want something like "x, y, z" that can be edited to update the vector type. I assumed that I could do so by adding a TypeConverter
derived class:
public class MyVectorConverter : TypeConverter
{
public override bool CanConvertFrom(ITypeDescriptorContext context,
Type sourceType)
{
if (sourceType == typeof(string))
return true;
//...
return base.CanConvertFrom(context, sourceType);
}
public override bool CanConvertTo(ITypeDescriptorContext context,
Type destinationType)
{
if (destinationType == typeof(string))
return true;
//...
return base.CanConvertTo(context, destinationType);
}
public override object ConvertFrom(ITypeDescriptorContext context,
System.Globalization.CultureInfo culture,
object value)
{
if (value is string)
{
MyVector MyVector;
//Parse MyVector from value
return MyVector;
}
return base.ConvertFrom(context, culture, value);
}
public override object ConvertTo(ITypeDescriptorContext context,
System.Globalization.CultureInfo culture,
object value,
Type destinationType)
{
if (destinationType == typeof(string))
{
string s;
//serialize value to string s
return s;
}
//...
return base.ConvertTo(context, culture, value, destinationType);
}
}
and associating it with my struct:
[TypeConverter(typeof(MyVectorConverter))]
public class MyVector { //... }
This appears to complete half of the battle. I can see MyVectorConverter
getting called into, but something is amiss. It is called to see if it knows how to convert to string, then it is called to convert to string. However, it is never queried to see if it can convert FROM string nor to actually do the conversion. Furthermore, right after an edit in the textbox, the old value is immediately replaced (another CanConvertTo and ConvertTo sequence, restoring the old value). The end result is that the newly typed entry in the text box is reverted immediately after it is applied.
I feel as if there is just something simple missing. Is there? Is this entire project/approach doomed to failure? Does anyone else attempt such madness? How does one bi-directionally bind a custom, multipart type to a string-based control?
Solution: Bizarrely, all that is needed is for the "formatting" to be enabled on the Binding object. (thanks, Jon Skeet):
textBox.DataBindings.Add("Text", this, "MyVectorProperty"); //FAILS
textBox.DataBindings.Add("Text", this, "MyVectorProperty", true); //WORKS!
Oddly, all that my MSDN mentions about this parameter (formattingEnabled) is:
"true to format the displayed data; otherwise, false"
It mentions nothing about it being a requirement for the data to come back from the control (under these conditions).