5 ene 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.

3 comentarios:

  1. 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

    ResponderEliminar
  2. 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.

    ResponderEliminar
  3. Hola,
    Muchas gracias,muy utíl el ejemplo.

    ResponderEliminar