2013-08-22 8 views
12

Ho un DataGridView in cui carico i dati da un database del server SQL. Quando carico i dati ci vuole molto tempo.Barra di avanzamento per il caricamento dei dati in DataGridView tramite DataTable

Vorrei fornire all'utente le informazioni sul caricamento dei dati. Posso chiederti qual è il modo migliore per connettere lo Progressbar quando i dati vengono caricati nello DataGridView?

Non voglio che qualcuno faccia un codice pienamente funzionante per me. Vorrei solo sapere come può essere fatto.

Vedo qualcuno che ha assegnato la mia domanda con la taglia. Vorrei dire che al momento sto usando questo codice che vorrei appagare se fosse adatto.

DTGdataTable = new DataTable(); 
SqlDataAdapter SDA = new SqlDataAdapter 
SDA.Fill(DTGdataTable); 
dataGridView1.DataSource = DTGdataTable ; 

Grazie a tutti per il vostro tempo.

+0

possibile duplicato di [Vuoi mostrare l'animazione mentre datagridview sta riempiendo di dati] (http://stackoverflow.com/questions/6294374/want-to-show-animation-while-datagridview-is-filling-with-data) – Shaharyar

+1

Se tutto ciò che serve è che l'utente sappia che sta caricando, avvolgi il tuo codice con 'this.Cursor = Cursors.Wait;' 'this.Cursor = Cursors.Default;' – wruckie

risposta

17

Se il problema è che ci vuole tempo per recuperare i dati dal database, ho una possibile soluzione per voi:

private void buttonLoad_Click(object sender, EventArgs e) 
    { 
     progressBar.Visible = true; 
     progressBar.Style = ProgressBarStyle.Marquee; 
     System.Threading.Thread thread = 
      new System.Threading.Thread(new System.Threading.ThreadStart(loadTable)); 
     thread.Start(); 
    } 

    private void loadTable() 
    { 
     // Load your Table... 
     DataTable table = new DataTable(); 
     SqlDataAdapter SDA = new SqlDataAdapter(); 
     SDA.Fill(table); 
     setDataSource(table); 
    } 

    internal delegate void SetDataSourceDelegate(DataTable table); 
    private void setDataSource(DataTable table) 
    { 
     // Invoke method if required: 
     if (this.InvokeRequired) 
     { 
      this.Invoke(new SetDataSourceDelegate(setDataSource), table); 
     } 
     else 
     { 
      dataGridView.DataSource = table; 
      progressBar.Visible = false; 
     } 
    } 

Inserire il metodo di caricamento dei dati in un altro thread e impostare l'origine dati al termine. Ci dovrebbe essere un richiamo richiesto. Se si desidera visualizzare i valori percentuali nella barra di avanzamento, non utilizzare lo stile "Marquee" e aggiungere un'altra funzione e delegare che è possibile richiamare per impostare il valore della barra di avanzamento.

Se il problema è legato ai dati nella griglia, non è possibile inserire il collegamento in un altro thread e si può visualizzare un popup di avanzamento eseguito in un altro thread.

Spero che questo aiuti.

-4

1.Scarica un ajax loader.gif da google.

2.Replace quell'immagine con questo codice ..

3.Impostare tempo di conseguenza ..

<div id="spinner" style="display: none;"> 
<span id="ss" style="float: left; margin-left: 50% !Important; margin-top: 22% !Important;"> 
<img src="ajax-pink-loader.gif" alt="Loading..." /> 
</span> 
</div> 

    $("#ssubmit").click(function() { 
     $("#spinner").show(); 
     setInterval(function() { 
      $("#spinner").hide(); 
     }, 20000); 
    }); 
+0

Le domande sono contrassegnate per *** Winforms ***. IMHO, *** 'meglio ELIMINARE la domanda ***. *** _NON risposta utile._ – Kiquenet

3

Prova questo ... Questo dovrebbe essere la via più veloce ...

1) Add a button control. 
2) Add a datagridview control. 
3) Add a single column into the datagridview control. 
4) Add a progressbar control. 
5) Leave them all with default names. 

sotto l'evento button1_Click, aggiungere questo pezzo di codice ...

int maxnumber = 1000; 
progressBar1.Value = 0; 
progressBar1.Maximum = maxnumber; 
for (int x = 0; x <= maxnumber - 1; x++) 
{ 
    Application.DoEvents(); 
    dataGridView1.Rows.Add(new string[] {Convert.ToString(x)}); 
    progressBar1.Value += 1; 
    label1.Text = progressBar1.Value.ToString(); 
} 

Questo è tutto. Modifica in base alle tue esigenze. Questo non è il codice esatto completo che vuoi ma dovrebbe farti iniziare. Mi sono preso la libertà di dichiarare il numero massimo per mantenere il limite della barra di avanzamento. Nel tuo caso, questo dovrebbe essere il conteggio delle righe del tuo database e viene sottratto di 1 poiché l'indice inizia sempre con zero :)

Il metodo sopra riportato è a thread singolo, il che significa che non è ancora possibile eseguire il multitasking mentre il ciclo è ancora attivo non è ancora finito. In alcuni casi, a seconda dell'algoritmo del codice, l'utilizzo del metodo a thread singolo potrebbe essere più rapido rispetto a quello per il percorso di multithreading. Ad ogni modo, il secondo metodo sarebbe usare un backgroundworker. Questo è più comunemente preferito dalle persone poiché l'utente può ancora fare cose mentre l'elenco viene caricato. Un po 'come installatori in cui è possibile annullare l'installazione anche se è nel mezzo di fare qualcosa. Il sito qui sotto dovrebbe iniziare. Il codice è in VB.NET, ma può essere facilmente convertito in C# :)

http://social.msdn.microsoft.com/Forums/vstudio/en-US/efd7510c-43ed-47c4-86a3-1fa350eb0d30/fill-datagridview-using-backgroundworker-progressbar?forum=vbgeneral

+3

'Application.DoEvents'? Un BackgroundWorker non sarebbe un consiglio migliore? – LarsTech

+0

@LarsTech Sì, hai ragione. Un backgroundworker è una scelta migliore poiché Application.DoEvents è ancora single threaded. È la ragione per cui ho detto la via più veloce, indipendentemente da quale sia la migliore. Potrei fare anche un metodo di backgroundworker dopo aver fatto colazione :) Grazie per averlo indicato Sir :) –

+0

@ chris_techno25 Apprezzo che tu abbia postato questa risposta. Per quanto vedo, posso collegarlo a string [], in quel momento avrei potuto usarlo ma ora Iam usando 'SqlDataAdapter' e caricando in datagridview come' SDA.Fill (DataTable); 'La tua soluzione funzionerà anche con il DataTable - 'dataGridView1.DataSource = DataTable;' – Marek

2

Il problema è il caricamento di tutti i dati insieme e il ritorno dal database. È necessario ottenere il progresso del caricamento dei dati. Questo può essere fatto dal database.

  1. Ottieni il conteggio delle righe di dati dal database. (Questa query restituirebbe un singolo numero, quindi sarebbe più veloce).

  2. Ottenere i dati in parti (Divide & strategia di conquista), è possibile utilizzare query di database OFFSET e FETCH. (Questa è la parte di ritorno dei dati per ogni chiamata) OFFSET e FETCH è disponibile su un altro database. In MSSQL, è stato introdotto nella versione 2012.

Quando stiamo ottenendo i dati in parti dal server, possiamo calcolare il progresso.

+0

Anche per le versioni di database meno recenti puoi utilizzare ROW_NUMBER() per ottenere i risultati in parti. –

2

All'interno del codice, questa linea prenderà la maggior parte del tempo di elaborazione:

SDA.Fill(DTGdataTable); 

Quindi penso che la cosa più importante è quello di tenere traccia dei progressi, mentre questo è in esecuzione. Per fare ciò, devi prima sapere quante file ti aspetti. SQLDataAdapter non può fornire queste informazioni, quindi è necessario eseguire prima una query COUNT (*) extra per ottenere questo numero. Puoi quindi usarlo come Massimo sul tuo ProgressBar.

Il mio codice di caricamento effettivo si basa sulla soluzione di Michael Hofmeiers, ma invece di utilizzare ProgressBar in modalità Marquee, lo alimenterei con dati di avanzamento reali da un controllo timer. Quindi nel tuo modulo, aggiungi un controllo Timer (denominato progressTimer nel mio esempio), imposta il suo Intervallo su 100 msec e Abilitato su falso. Il codice diventa allora:

private DataTable table = null; 

private void buttonLoad_Click(object sender, EventArgs e) 
{ 
    // TODO: Select the row count here and assign it to progressBar.Maximum 

    progressBar.Visible = true;    
    System.Threading.Thread thread = 
     new System.Threading.Thread(new System.Threading.ThreadStart(loadTable)); 
    thread.Start(); 
    progressTimer.Enabled = true; 
} 

private void loadTable() 
{ 
    // Load your Table... 
    this.table = new DataTable(); 
    SqlDataAdapter SDA = new SqlDataAdapter(); 
    SDA.Fill(table); 
    setDataSource(table); 
} 

internal delegate void SetDataSourceDelegate(DataTable table); 
private void setDataSource(DataTable table) 
{ 
    // Invoke method if required: 
    if (this.InvokeRequired) 
    { 
     this.Invoke(new SetDataSourceDelegate(setDataSource), table); 
    } 
    else 
    { 
     progressTimer.Enabled = false; 
     dataGridView.DataSource = table; 
     progressBar.Visible = false; 
    } 
} 

private void progressTimer_Tick(object sender, EventArgs e) 
{ 
    if (this.table != null) 
     progressBar.Value = this.table.Rows.Count; 
} 

Quando si esegue questo, l'applicazione rimarrà reattivo durante il caricamento, e vedrete la ProgressBar cambia per riflettere il numero di righe caricate. Solo alla fine (quando si imposta DataSource su DataGridView) l'applicazione sembrerà "bloccata", ma non penso che ci sia un modo per evitarlo. Puoi eseguire questa operazione solo dal thread principale, quindi è inevitabile che l'interfaccia utente non risponda. Ma nel mio test, DataGridView gestisce facilmente le righe 300K + in circa un secondo, quindi questo non dovrebbe essere un grosso problema.