c# winforms data-binding textbox typeconverter

c# - ¿Cómo puede un enlace de datos un tipo personalizado para TextBox.Text?



winforms data-binding (1)

Tengo un tipo de c # personalizado como (solo un ejemplo):

public class MyVector { public double X {get; set;} public double Y {get; set;} public double Z {get; set;} //... }

Y quiero que se enlace con TextBox.Text:

TextBox textBox; public MyVector MyVectorProperty { get; set;} //... textBox.DataBindings.Add("Text", this, "MyVectorProperty");

Básicamente, necesito conversión ay de una cadena para mi tipo de valor personalizado. En el cuadro de texto, quiero algo como "x, y, z" que se puede editar para actualizar el tipo de vector. Supuse que podía hacerlo agregando una clase derivada 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); } }

y asociándolo con mi estructura:

[TypeConverter(typeof(MyVectorConverter))] public class MyVector { //... }

Esto parece completar la mitad de la batalla. Puedo ver a MyVectorConverter siendo llamado, pero algo anda mal. Se llama para ver si sabe cómo convertir a cadena, luego se llama para convertir a cadena. Sin embargo, nunca se consulta para ver si puede convertir FROM cadena ni hacer realmente la conversión. Además, justo después de una edición en el cuadro de texto, el valor anterior se reemplaza inmediatamente (otra secuencia CanConvertTo y ConvertTo, restaurando el valor anterior). El resultado final es que la entrada recién ingresada en el cuadro de texto se revierte inmediatamente después de que se aplica.

Siento que simplemente falta algo simple. ¿Esta ahí? ¿Todo este proyecto / enfoque está condenado al fracaso? ¿Alguien más intenta tal locura? ¿Cómo se vincula bi-direccionalmente un tipo personalizado de varias partes a un control basado en cadenas?

Solución: Curiosamente, todo lo que se necesita es que el "formateo" esté habilitado en el objeto de enlace. (gracias, Jon Skeet):

textBox.DataBindings.Add("Text", this, "MyVectorProperty"); //FAILS textBox.DataBindings.Add("Text", this, "MyVectorProperty", true); //WORKS!

Curiosamente, todo lo que mi MSDN menciona sobre este parámetro (formattingEnabled) es:

"verdadero para formatear los datos mostrados; de lo contrario, falso"

No menciona nada sobre que sea un requisito para que los datos vuelvan del control (en estas condiciones).


¡Lo tengo!

Establezca la propiedad Binding.FormattingEnabled en verdadero. Esto parece hacer que todo funcione. Puede hacerlo con una sobrecarga del método ControlBindingsCollection.Add que toma un parámetro booleano al final. Es extraño que haya funcionado de una forma pero no de la otra antes, pero ciertamente mi aplicación de prueba ahora funciona ...

(Respuesta anterior a continuación)

No me sorprendería en absoluto si el hecho de que tienes una estructura en lugar de una clase fuera importante aquí, así como la forma en que estás usando los campos en lugar de las propiedades.

Pruebe con una clase que use propiedades autoejecutables en su lugar:

public class MyClass { public int IntPart { get; set; } public string StringPart { get; set; } //... }

Esto bien puede no ser la raíz del problema, pero el uso de una estructura mutable con campos públicos es solo pedir problemas de OMI.

EDITAR: Como mencioné en los comentarios, ahora tengo un ejemplo en funcionamiento. El Binding.Parse se está levantando con el valor correcto. Ahora para descubrir por qué el TypeConverter no se llama ...

EDITAR: He encontrado un artículo útil que describe el enlace en más detalle. Parece sugerir que el convertidor de tipos solo se utiliza para convertir "a" otro tipo, por lo que necesitaría el convertidor de tipos de string para saber cómo convertir al tipo personalizado. Esto me parece bastante extraño, hay que admitirlo, pero hay otras dos opciones:

  • Utilice los eventos Format and Parse de Binding para realizar la conversión
  • Hacer que el tipo implemente IConvertible

Ninguno de estos apela de la misma manera, pero pueden ser una solución suficiente para usted. Estoy seguro de que hay una forma de hacer que esto funcione con TypeConverters, pero estoy impactado si puedo verlo en este momento.