2013-08-22 45 views
12

Mam DataGridView, w którym ładuję dane z bazy danych serwera SQL. Kiedy ładuję dane, zajmuje to dużo czasu.Pasek postępu do ładowania danych do DataGridView przy użyciu DataTable

Chciałbym podać informacje użytkownika, że ​​dane są ładowane. Czy mogę zapytać, jaki jest najlepszy sposób połączenia Progressbar podczas ładowania danych do DataGridView?

Nie chcę, żeby ktokolwiek zrobił dla mnie w pełni działający kod. Chciałbym tylko wiedzieć, jak można to zrobić.

Widzę, że ktoś nagrodził moje pytanie nagrodą grzecznościową. Chciałbym powiedzieć, że w tej chwili używam tego kodu, który byłby aprobowany, gdyby pasował.

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

Dziękuję wszystkim za poświęcony czas.

+0

możliwy duplikat [Chcesz pokazać animację, gdy datagridview jest wypełniony danymi] (http://stackoverflow.com/questions/6294374/want-to-show-animation-while-datagridview-is-filling-w-data) – Shaharyar

+1

Jeśli wszystko, czego potrzebujesz, to to, że użytkownik wie, że się ładuje, zapisz swój kod za pomocą 'this.Cursor = Cursors.Wait;' 'this.Cursor = Cursors.Default;' – wruckie

Odpowiedz

17

Jeśli problem jest to, że trwa długo, aby pobrać dane z bazy danych, mam możliwe rozwiązanie dla Ciebie:

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; 
     } 
    } 

Umieść metodę ładowania danych do innego wątku i ustaw źródło danych po zakończeniu. Powinno być wymagane wywołanie. Jeśli chcesz pokazywać wartości procentowe na pasku postępu, nie używaj stylu "Marquee" i dodawaj innej funkcji i deleguj, do której możesz wywołać ustawienie wartości paska postępu.

Jeśli powiązanie danych z siecią jest problemem, nie można umieścić powiązania w innym wątku i można wyświetlić okno postępu, które działa w innym wątku.

Mam nadzieję, że to pomoże.

-4

1. Pobierz ajax loader.gif z google.

2.replace tego obrazu z tego kodu ..

czas

3.Ustaw odpowiednio ..

<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

Pytania są oznaczone jako *** WinForms ***. IMHO, *** "lepiej USUŃ pytanie" ***. _NOT przydatne answer._ – Kiquenet

3

Spróbuj tego ... To powinno być najszybsza trasa ...

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. 

Pod zdarzenia button1_Click dodać ten kawałek kodu ...

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(); 
} 

To wszystko. Edycja dostosowana do Twoich potrzeb. To nie jest kompletny kod, który chcesz, ale powinien zacząć. Mogłem zadeklarować maksimum, aby utrzymać limit paska postępu. W twoim przypadku powinna to być liczba wierszy bazy danych i odejmowana przez 1, ponieważ indeks zawsze zaczyna się od zera :)

Powyższa metoda jest jednokrotnym gwintem, co oznacza, że ​​nadal nie można wykonywać wielozadaniowości, podczas gdy pętla nadal jeszcze nie zostało zrobione. W niektórych przypadkach, w zależności od algorytmu kodu, użycie metody z pojedynczym gwintem może być szybsze niż przejście do trasy wielowątkowej. W każdym razie druga metoda polegałaby na pracy w tle. Jest to najczęściej preferowane przez ludzi, ponieważ użytkownik może nadal robić rzeczy podczas ładowania listy. Coś w rodzaju instalatorów, w których można anulować instalację, nawet jeśli jest w trakcie robienia czegoś. Poniższa strona internetowa powinna zacząć. Kod jest w VB.NET, ale można łatwo przekształcić w 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'? Czy nie lepiej doradziłby pracownikowi w tle? – LarsTech

+0

@LarsTech Yup masz rację. Praca w tle jest lepszym wyborem, ponieważ Application.DoEvents jest wciąż pojedynczym wątkiem. To jest powód, dla którego powiedziałem najszybszą trasę, niezależnie od tego, która z nich jest lepsza. Mogę zrobić też metodę pracowniczą po tym, jak jem śniadanie :) Dziękuję za wskazanie tego Sir :) –

+0

@ chris_techno25 Doceniam, że wysłałeś tę odpowiedź. O ile widzę, mogę podłączyć go do napisu [], w tym czasie mogłem go użyć, ale teraz używam 'SqlDataAdapter' i ładuję do datagridview jak' SDA.Fill (DataTable); 'Czy twoje rozwiązanie działa również z DataTable - 'dataGridView1.DataSource = DataTable;' – Marek

2

Problem polega na tym, że wszystkie dane są ładowane razem i wracają z bazy danych. Musisz uzyskać postęp ładowania danych. Można to zrobić z bazy danych.

  1. Uzyskaj liczbę wierszy danych z bazy danych. (To zapytanie zwróci pojedynczą liczbę, więc będzie szybciej).

  2. Pobierz dane w częściach (Podziel się & strategią zdobywania), możesz użyć zapytań bazy danych OFFSET i FETCH. (Jest to część zwrotna danych dla każdego połączenia) OFFSET i FETCH są dostępne w różnych bazach danych. W MSSQL został wprowadzony w wersji 2012.

Kiedy otrzymujemy dane w częściach z serwera, możemy obliczyć postęp.

+0

Również dla starszych wersji bazy danych możesz użyć ROW_NUMBER(), aby uzyskać wyniki w częściach. –

2

w kodzie, linia ta będzie trwać przez większość czasu przetwarzania:

SDA.Fill(DTGdataTable); 

Więc myślę, że najważniejszą rzeczą jest, aby śledzić postęp podczas gdy ten jest wykonywany. Aby to zrobić, najpierw musisz wiedzieć, ile wierszy się spodziewasz. SQLDataAdapter nie może dostarczyć tych informacji, więc aby uzyskać ten numer, należy najpierw uruchomić dodatkowe zapytanie COUNT (*). Następnie możesz użyć tego jako maksimum na pasku postępu.

Mój aktualny kod ładowania jest oparty na rozwiązaniu Michaela Hofmeiersa, ale zamiast używać ProgressBar w trybie Markizy, podawałbym go z rzeczywistymi danymi postępu z Kontroli Timera. Tak więc w formularzu dodajesz kontrolkę Timer (o nazwie progressTimer w moim przykładzie), ustaw jej interwał na 100 ms i Enabled na false. Następnie kod staje:

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; 
} 

Po uruchomieniu, aplikacja pozostanie czuły podczas załadunku, a zobaczysz ProgressBar zmieniając odzwierciedlać liczbę wierszy załadowanych. Dopiero na końcu (gdy ustawisz DataSource w DataGridView) aplikacja będzie wyglądała na "zawieszoną", ale nie sądzę, że jest sposób na uniknięcie tego. Tę operację można wykonać tylko z głównego wątku, więc nieuniknione jest, że interfejs użytkownika przestaje odpowiadać. Ale w moim teście DataGridView z łatwością radzi sobie z wierszami 300K + w ciągu sekundy, więc nie powinno to stanowić większego problemu.

Powiązane problemy