У меня есть собственный тип С#, например (просто пример):
public class MyVector
{
public double X {get; set;}
public double Y {get; set;}
public double Z {get; set;}
//...
}
И я хочу, чтобы он привязывался к TextBox.Text:
TextBox textBox;
public MyVector MyVectorProperty { get; set;}
//...
textBox.DataBindings.Add("Text", this, "MyVectorProperty");
По сути, мне нужно преобразование в строку и обратно для моего пользовательского типа значения. В текстовом поле я хочу что-то вроде «x, y, z», которое можно редактировать, чтобы обновить тип вектора. Я предположил, что смогу сделать это, добавив производный класс TypeConverter
:
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);
}
}
и связывая его с моей структурой:
[TypeConverter(typeof(MyVectorConverter))]
public class MyVector { //... }
Кажется, на этом половина битвы завершена. Я вижу, что MyVectorConverter
вызывают, но что-то не так. Он вызывается, чтобы узнать, знает ли он, как преобразовать в строку, а затем вызывается для преобразования в строку. Тем не менее, он никогда не запрашивается, может ли он преобразовать строку FROM или действительно выполнить преобразование. Кроме того, сразу после редактирования в текстовом поле старое значение немедленно заменяется (другая последовательность CanConvertTo и ConvertTo, восстанавливающая старое значение). Конечным результатом является то, что вновь введенная запись в текстовом поле возвращается сразу же после ее применения.
Я чувствую, как будто чего-то простого не хватает. Есть? Весь этот проект/подход обречен на провал? Кто-нибудь еще пытается такое безумие? Как можно двунаправленно связать пользовательский составной тип со строковым элементом управления?
Решение. Как ни странно, все, что нужно, — это включить «форматирование» для объекта Binding. (спасибо, Джон Скит):
textBox.DataBindings.Add("Text", this, "MyVectorProperty"); //FAILS
textBox.DataBindings.Add("Text", this, "MyVectorProperty", true); //WORKS!
Как ни странно, все, что мой MSDN упоминает об этом параметре (formattingEnabled), это:
"true для форматирования отображаемых данных; в противном случае - false"
В нем ничего не говорится о том, что данные должны возвращаться из системы управления (в этих условиях).