posts - 35,  comments - 476,  trackbacks - 4

Pues eso... hay varias cosas que no me terminan de cuadrar sobre el como funciona el DataGridView cuando se vincula (mmm... ata?), cuando se hace data-binding para entendernos contra un objeto de negocio propio.

Supongamos que tengo la siguiente clase:

public class Activity

{

private Action _exitAction;

private bool _endStateActivity;

private string _name;

public string Name

{

get { return _name; }

set { _name = value; }

}

public bool EndActivity

{

get { return _endStateActivity; }

set { _endStateActivity = value; }

}

[TypeConverter(typeof(ActionTypeConverter))]

public Action EntryAction

{

get { return _enterAction; }

set { _enterAction = value; }

}

}

La clase Action no importa para lo que quiero contar, imaginaosla como querais... podemos suponer que tiene una propiedad Name de tipo String.

Tengo también otra clase llamada State que entre otras cosas tiene una propiedad de tipo List, llamada Activities.

Creo un object data binding: Data -> Add New DataSource -> Object y selecciono la clase State.

Eso me crea un object data binding parecido a ese:

(Nota: En mi caso la clase Activity tiene también propiedades DoAction y ExitAction que son de tipo Action)

Luego, arrastro la propiedad Activities en un form, y me aparece automáticamente un dataviewgrid vinculado. Hasta ahí todo perfecto.

Ahora empieza la pesadilla... Cual es mi idea? Tengo varios tipos de Acciones que se pueden asignar a la propiedad EntryAction. Desde la grid vinculada me gustaría que se desplegara una combo con los distintos tipos de acciones que admito (p.ej. PlaySound y PlaySequence). Cuando el usuario escoja un valor de la combo, el datagridview debería crear un objeto Action, concreto (bueno, de hecho me gustaría que creara un objeto de una cierta clase derivada de Action. Si el usuario escoje PlaySound en la combo quiero que se cree un objeto de la clase PlaySound).

El primer paso es sencill En la DataGridView indico que quiero modificar las columnas y indico que la columna EntryAction es de tipo DropDownList. La cosa queda més o menos así:

Luego añado dos items a la columna EntryAction (dos cadenas) con los valores "PlaySound" y "PlaySequence" para que el usuario pueda escojer.

Finalmente creo la clase ActionTypeConverter que deriva de TypeConverter cuya finalidad es convertir una cadena a un objeto Action y viceversa. Defino los métodos:

public

override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)

public

override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)

public

override object ConvertFrom(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value)

public

override object ConvertTo(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, Type destinationType)

Lo hago para que el CanConvertFrom y el CanConverTo indiquen true sólo si se desea convertir desde/a cadena e implemento el ConvertFrom para que devuelva una instancia de PlaySound o PlaySequence en función de si la cadena pasada es "PlaySound" o "PlaySequence". Finalmente el método ConvertTo hace lo contrario (devuelve una cadena "PlaySound" o "PlaySequence".

Ejecuto el programa y cuando escojo un valor de la combo:

Además ese error se repite ad-eternum cada vez que la DataViewGrid necesita refrescarse.

Tras unas cuantas lecturas por foros y demás, viendo que ese error se da un muchos casos, observo depurando que los métodos CanConvertFrom y ConvertFrom del ActionTypeConverter, pero los que convierten de Action a string no. Eso me extraña puesto que yo daba por supuesto que:

  1. La Grid llamaría a ConvertTo para pasar el objeto Action a una cadena y mostrar ese valor en la combo
  2. La Grid llamaría a ConvertFrom cuando se hubiese seleccionado un valor de la combo, para obtener un objeto Action (o en mi caso un objeto derivado de Action).

Pero, por alguna razón el punto (1)  no se lleva a cabo... :(

Luego también me llamó la atención el hecho de que en unos foros se mencionaba que una celda de tipo combo en la grid sólo podía mostrar valores que contuviera la propia combo, y me asaltó la duda... no estará comparando por Equals? En este caso el mensaje de error, tendría sentido puesto que en la combo había cadenas (String) que nunca serían iguales a objetos Action (aunque yo proporcionase un ConvertTo que por alguna oscura razón no se llamaba). Así que hice dos cosas: poblar la combo (myColumn.Items.AddRange(...)) con dos objetos Action (un PlaySound y un PlaySequence) y redefnir los métodos Equals de forma que todos los PlaySound sean iguales entre ellos y todos los PlaySequence sean iguales entre ellos.

Cuando ejecuté el programa en la combo no aparecía el nombre "PlaySound" o "PlaySequence" sinó el nombre completo de la clase... tal y como lo hace el ToString(), así que ya puestos lo redefiní también (total... me hacía falta un método para pasar de Action a cadena, no?).

Y al ejecutar... funcionó! En la combo se mostraba "PlaySound" y "PlaySequence" y al seleccionar un valor, se ejecutaba el ConvertFrom del TypeConverter.

Mis dudas principales son:

  1. Por qué la Grid es capaz de ejecutar el ConvertFrom del TypeConverter para obtener un objeto a partir de la cadena y no es capaz de ejecutar el ConvertTo para obtener una cadena a partir del objeto (será porque todos los objetos tienen ToString() ?)
  2. Por qué me obliga a poblar la columna usando objetos Action en lugar de cadenas? (Aunque bueno, esto segundo lo puedo llegar a entender pienso que debería ser posible poblar la combo con cadenas que fuesen representaciones válidas de objetos de negocio y que la grid fuera lo suficientemente lista como para espavilarse).

En fin, tu... que líos...

Editado @28/09: Vale... creo que ya se cuando llama al ConvertTo y cuando llama al ToString(): Para poblar la combo necesita cadenas, así que llama al ToString(). Si tengo eso:

Action a1 = new PlaySound("foo");

Action a2 = new PlaySequence("bar");

col.Items.AddRange(a1, a2);

Para poblar la combo llamará a a1.ToString() y a2.ToString().

Luego el ConvertTo lo llama cuando lee de la fuente de datos, y la cadena resultante es la que intenta mostrar en la combo.

posted on Thursday, September 28, 2006 4:58 PM

Post a new comment about this topic
Title  
Name  
Url

Comments   
Protected by Clearscreen.SharpHIPEnter the code you see: