05/01/2009

Recursividad + Invoke = Procedimiento Thread Safe

Este es más un apunte que un gran conocimiento, pero puede ayudar a más de uno, la idea es mostrar datos en la UI desde un hilo diferente del principal, por ejemplo: creamos un hilo que se encargue de ir a buscar datos a la BDD y los muestre en una grilla cuando los reciba.

Cuando aprendí a usart Invoke lo que hacía era un método que mostraba los datos en la UI y otro que chequeaba si era necesario utilizar Invoke o no.

Public Sub MostrarDatos(Datos as DataSet)
If Me.InvokeRequired = True Then
Me.Invoke(New SetDataSource_Delegate(AddressOf SetDataSource), Datos)
Else
Me.SetDataSource(Datos)
End If
End Sub


Private Delegate Sub SetDataSource_Delegate(ds As DataSet)

Private Sub SetDataSource(ds As DataSet)
Me.DatagridView1.DataSource = ds
Me.DatagridView1.DataMember = ds.Tables(0).TableName
End Sub


Un tiempo después, como parte de mi eterna búsqueda por escribir mejor código, descubrí que podía simplificar todo eso usando una llamada recursiva y combinando ambos procedimientos en uno solo de la siguiente manera:

Private Delegate Sub MostrarDatos_Delegate(ds As DataSet)


Public Sub MostrarDatos(Datos as DataSet)
If Me.InvokeRequired = True Then
Me.Invoke(New MostrarDatos_Delegate(AddressOf MostrarDatos), Datos)
Else
Me.DatagridView1.DataSource = ds
Me.DatagridView1.DataMember = ds.Tables(0).TableName
End If
End Sub


Como se puede ver, el código queda más legible y no deja de ser eficiente, además de ahorrarnos un par de líneas... que en un formulario muy extenso puede ayudarnos bastante.

2 comentarios:

Lenin dijo...

Hola,
Mi pregunta estaría fuera de tema, espero me puedas ayudar. Tengo una clase en el cual un método es idéntico a un método de otra clase, la diferencia es que existe una línea donde llamo a un procedimiento de la clase misma, por esta razón no puedo poner a este evento en una clase madre.

La idea mas o menos es poder llamar a un solo método pero como parámetros indicar al método que hace diferente a ambás clases.

adjunto codigo de dichas clases.

METODO DE LA CLASE 1
public DataSet fnBuscarDatos()
{
try
{
SqlParameter[] parametros = fnMapeo(clsConstantes.OperacionBD.Buscar);
parametros[parametros.Length - 1].Direction = ParameterDirection.Output;
DataSet ds = new DataSet();
ds = this.fnConsultarDatos("logistics.pa_tb_Item", parametros);
return ds;
}
catch (System.Exception ex)
{
throw (ex);
}
}

METODO DE LA CLASE 2
public DataSet fnBuscarDatos()
{
try
{
SqlParameter[] parametros = fnMapeoDatos(clsConstantes.OperacionBD.Buscar);
parametros[parametros.Length - 1].Direction = ParameterDirection.Output;
DataSet ds = new DataSet();
ds = this.fnConsultarDatos("logistics.pa_tb_Clientes", parametros);
return ds;
}
catch (System.Exception ex)
{
throw (ex);
}
}

Cómo puedes ver los métodos son iguales salvo por el Método fnMapeo y fnMapeoDatos y el nombre de mi store procedure

Gracias de antemano por tu ayuda. y Perdón por lo largo del mensaje

Lenin

The Keeper Of The 7 Keys dijo...

Yo creo que deberías pasar un delegado de la función por parámetro, y luego en el cuerpo de tu función única invocas al delegado en lugar de llamar a la función específica.