C #, 3 Layers, Windows Forms - Improve Performance

3

I need to fill out a datagridview with more than 7,000 records that I get through a method that returns a generic list of objects. My problem is that when I assign it to datagriview.DataSource = LN.ObtainAll () positions; through the load method of the Form, it is fried and blocks the complete application for about 30 seconds and after that, the grid is filled and everything is fine!.

1- How to implement a progress bar using async and await ?, to inform the user of the progress of that task.

Note: I use programming in 3 layers, the Form is in a project that belongs to the presentation layer, which is communicated to the data access layer through the business layer. (Visual Studio 2015, C # and MySql).

// Proyecto Entidades:
public sealed class Posicion
{
    public int IdPosicion { get; set; }
    public Fila Fila { get; set; }
    public int Numero { get; set; }
    public string NombreCompleto => string.Format(CultureInfo.CurrentCulture, "{0} - {1}", Fila.NombreCompleto, Numero);

}

// Proyecto AccesoDatos: PosicionAD.cs  
public static List<Posicion> ObtenerTodos()
{
        var lista = new List<Posicion>();
        const string sql = @"spu_posicion_obtenertodos";

        using (var lector = helper.ExecuteReader(CommandType.StoredProcedure, sql))
        {
            while (lector.Read())
            {
                lista.Add(CargarPosicion(lector));
            }
            return lista;
        }
}

private static Posicion CargarPosicion(IDataReader dr)
{

        var ordinalIdPosicion = dr.GetOrdinal("idposicion");
        var ordinalIdFila = dr.GetOrdinal("id_Fila");
        var ordinalNumero = dr.GetOrdinal("numero");


        var colCount = dr.FieldCount;
        var values = new object[colCount];

        var objPosicion = new Posicion();
        dr.GetValues(values);

        objPosicion.IdPosicion = Convert.ToInt32(values[ordinalIdPosicion]);
        objPosicion.Fila = FilaAD.ObtenerPorId(Convert.ToInt32(values[ordinalIdFila]));
        objPosicion.Numero = Convert.ToInt32(values[ordinalNumero]);

        return objPosicion;
}


// Proyecto LogicaNegocio: PosicionLN.cs    
public static List<Posicion> ObtenerTodos()
{
    return PosicionAD.ObtenerTodos();
}

// Proyecto Presentacion: FrmPosicion.cs
private void FrmPosicion_Load(object sender, EventArgs e)
{

    dgvDatosPosicion.AutoGenerateColumns = false;
    dgvDatosPosicion.DataSource = PosicionLN.ObtenerTodos();


}
    
asked by Geronimo Fernandez 16.07.2017 в 20:08
source

3 answers

1

Do not use the BackgroundWorker unless you are anchored to old versions of .Net framework.

The recommendable thing from .Net 4.5 is to use async and await:

public static async Task<List<Posicion>> ObtenerTodos()
{
    return Task.Run(() => {
        var lista = new List<Posicion>();
        const string sql = @"spu_posicion_obtenertodos";

        using (var lector = helper.ExecuteReader(CommandType.StoredProcedure, sql))
        {
            while (lector.Read())
            {
                lista.Add(CargarPosicion(lector));
            }
            return lista;
        }
    });
}

public static async Task<List<Posicion>> ObtenerTodos()
{
    return await PosicionAD.ObtenerTodos();
}


private async void FrmPosicion_Load(object sender, EventArgs e)
{
    dgvDatosPosicion.AutoGenerateColumns = false;
    dgvDatosPosicion.DataSource = await PosicionLN.ObtenerTodos();
}

I see a lot of people recommending old methods when async and await have been used for a long time.

    
answered by 28.03.2018 / 23:30
source
0

You need to implement a BackgroundWorker, in this way you can perform the loading of data from a different task than the one executed when the form is loading and prevent the user interface from stopping while it is processing:

var bw = new BackgroundWorker();
private void Form1_Load(object sender, EventArgs e)
{
     //Eventos
     bw.DoWork += Bw_DoWork;
     bw.ProgressChanged += Bw_ProgressChanged;
     bw.RunWorkerCompleted += Bw_RunWorkerCompleted;

    //Inicializa el backgroundworker
    if (!bw.IsBusy)
         bw.RunWorkerAsync();
}

private void Bw_DoWork(object sender, DoWorkEventArgs e)
{
   //Ejecuta el proceso
   dgvDatosPosicion.AutoGenerateColumns = false;
   dgvDatosPosicion.DataSource = PosicionLN.ObtenerTodos();

   //Notifica el porcentaje de proceso
   bw.ReportProgress(/*####*/);
}

private void Bw_ProgressChanged(object sender, ProgressChangedEventArgs e)
{ 
   //mostrar este valor en un ProgressBar
   var percent = e.ProgressPercentage;
}

private void Bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
    Debug.Write("Completado!");
}
    
answered by 01.08.2017 в 00:18
0

In several of my projects, I have to load several datagrids with quite large numbers of rows. What I usually do is load all the data from the init of the application with sync and await methods so when loading the views of the grids we have the data faster because they are already in memory.

I hope this comment helps you.

Greetings.

    
answered by 10.08.2018 в 14:02