Estoy tratando de devolver DataTable de otra clase usando hilo, pero el hilo no devuelve DataTable. Si bien no usa el hilo, funciona bien.

public class reatail
{
 DataTable order_dt = new DataTable();
    public DataTable loadAllOrder()
    {

        OleDbConnection co = new OleDbConnection();
        co.ConnectionString = @"Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" + sd + "bowoni.accdb";
        string loadAll = "select * from allorder";
        co.Open();
        OleDbCommand cc = new OleDbCommand(loadAll, co);
        OleDbDataAdapter ad = new OleDbDataAdapter(cc);
        ad.Fill(order_dt);
        return order_dt;
    }
}



public partial class RecieveOrder : Form
{

    DataTable dy = new DataTable();
    reatail r = new reatail();
    Thread t;
    public void storeToStock()
    {
        //DataTable dy = new DataTable();
        Thread th=new Thread(()=>dy=r.loadAllOrder());
        th.Start();
        foreach(DataRow row in dy.Rows)
        {
            MessageBox.Show(row[0].ToString());
        }
    }
}
1
mofidul 1 sep. 2016 a las 05:33

2 respuestas

La mejor respuesta

Está intentando acceder al valor de retorno incluso antes de que su hilo haya terminado de ejecutarse. Necesita hacer th.Join(); antes de comenzar a iterar las filas en la tabla usando foreach loop. Aquí sabrás como podrás hacerlo:

public partial class RecieveOrder : Form
{

    DataTable dy = new DataTable();
    reatail r = new reatail();
    Thread t;
    public void storeToStock()
    {
        //DataTable dy = new DataTable();
        Thread th=new Thread(()=>dy=r.loadAllOrder());
        th.Start();
        //wait for the thread to finish its execution and get the data from backend DB.
        th.Join();
        //now iterate the rows retrieved from DB
        foreach(DataRow row in dy.Rows)
        {
            MessageBox.Show(row[0].ToString());
        }
    }
}
3
RBT 1 sep. 2016 a las 03:09

Hay algunas cosas que van mal en su código.

Para comenzar, el problema al que se enfrenta es que está iniciando un hilo, pero en lugar de permitir que termine, está tratando de obtener el resultado de inmediato. Debe emplear algún mecanismo para saber cuándo finaliza el hilo para poder continuar el trabajo en el hilo de la interfaz de usuario. Usar th.Join() no es el mejor enfoque, ya que bloquea el hilo de la IU mientras se carga la tabla de datos.

Lo más fácil en estos días es emplear Task Parallel Library (TPL) para fijar y administrar sus hilos por usted.

Antes de mostrarles cómo solo quería comentar un par de cosas más.

En su clase reatail tiene la variable order_dt como un campo y crea una instancia de ella solo una vez. Esto significa que en cada lugar en el que se llame a loadAllOrder obtendrá una referencia a la misma tabla y esa tabla continuará llenándose con más y más registros duplicados. Desea mover el campo dentro del método loadAllOrder para evitarlo.

Además, en RecieveOrder declara dy instanciando un nuevo DataTable, pero luego reasigna esa variable con su llamada a loadAllOrder. Eso es un pequeño desperdicio. Es mucho mejor mantener limpio el código y evitar que se creen objetos innecesarios.

Así que es mejor que hagas esto:

public class reatail
{
    public DataTable loadAllOrder()
    {
        DataTable order_dt = new DataTable();
        OleDbConnection co = new OleDbConnection();
        co.ConnectionString = @"Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" + sd + "bowoni.accdb";
        string loadAll = "select * from allorder";
        co.Open();
        OleDbCommand cc = new OleDbCommand(loadAll, co);
        OleDbDataAdapter ad = new OleDbDataAdapter(cc);
        ad.Fill(order_dt);
        return order_dt;
    }
}

public partial class RecieveOrder : Form
{
    DataTable dy;
    reatail r = new reatail();
    public void storeToStock()
    {
        Task
            .Run(() => r.loadAllOrder())
            .ContinueWith(t =>
            {
                dy = t.Result;
                foreach (DataRow row in dy.Rows)
                {
                    MessageBox.Show(row[0].ToString());
                }
            }, TaskScheduler.FromCurrentSynchronizationContext());
    }
}

Esto no bloquea la interfaz de usuario, pero permite que la carga se ejecute en segundo plano.

La alternativa que podría ser incluso más sencilla es usar async / await. Tu storeToStock podría ser tan simple como:

public partial class RecieveOrder : Form
{
    DataTable dy;
    reatail r = new reatail();
    public async void storeToStock()
    {
        dy = await Task.Run(() => r.loadAllOrder());
        foreach (DataRow row in dy.Rows)
        {
            MessageBox.Show(row[0].ToString());
        }
    }
}
3
Enigmativity 1 sep. 2016 a las 04:40