[C#][WinForms] Wydajność bindowania DataGridView

0

Piszę sobie dll do robienia logów i aplikację WindowsForms do ich odczytywania/wyświetlania w sposób bardziej przejrzysty, niż suchy text. Dane są wczytywane z pliku/ów i wstępnie analizowane przy użyciu Background Worker'a. Dane mają być wyświetlane w DataGridView(DGV) i tu mam problem, bo przy dużej ilości wierszy binding trwa odczuwalnie długo, a w tym czasie forma staje się nieklikalna. Jest na to jakaś rada?
Przejrzałem to(link). Ustawiłem virtual mode i obsłużyłem zdarzenie DGVEvents_CellValueNeeded, z nadzieją, że będzie odpytywał tylko rysowane na bieżąco komórki, ale wywołuje się tyle razy, ile wierszy mu potrzeba.

0

NIe pamietam za dobrze, ale VirtualMode odpytyje Cie za pomoca eventow tylko o te dane, ktore grid sadzi ze sa mu aktualnie potrzebne - czyli N komorek * M wierszy aktualnie widocznych +- jeden/kilka wierszy ekstra. On te dane na czas wyswietlania TYCH wierszy sobie zapamieta, i nie zapyta o nic, dopoki user nie ruszy scrollbarem itp.

Nie ma opcji "odpytywania Ciebie podczas rysowania danej komorki", ponieaz JESLI Ty byś podczas rysowania omorki byl pytany o dane i Ty bys zaślamazarzyl na sekunde czy pół, to dopiero współczuje prędkości Twojego GUI. Grid sie Ciebie zapyta co najwyzej w momencie, gdy przygotowuje sie do narysowania czegos..


Jaki "binding" trwa dlugo? Na biezaco watek BGV wstawia wiersze? wiersz-po-wierszu? to sie nie dziwie ze Ci zgrzyta, same redrawy grida razy milion wierszy beda zgrzytac.. Zmien to na prace "paczkami" np. przenoszenie danych co 100, 1000 skonczonych wierszy, nie laduj pojedynczo - oszczedzisz na przerysowaniach.

Druga rzecz - JAK ladujesz dane do grida? Thread BGV poprzez invoke bezposrednio robi nowy wiersz w kontrolce? Jesli tak, zmien to natychmiast -chociazby- na uzycie BGV-reportprogress co wspomniane X wierszy, dodatkowo oszczedzisz na invoke. A w ogole - nie powinienes operowac na gridzie w ten sposob.. grid powienien miec jakies .DataSource ustawione na np. liste twoich wierszobiektow, BGV powinien nawalac wierszami (np. paczkami po 100/1000) do tej listy. zaleta jest taka, ze teraz mozesz to "rozpiąć", niech BGV nawala do listy tymczasowej, a jakis np. Timer co 0,5-3sek podmienia/skleja/(..) listy w gridzie<->tymczasowa.. Jezeli zas NIE potrzebujesz "animowanego"/"przyrostowego" ladowania grida, niech BGV przemieli sobie spokojnie wszystko, a dopiero jak skonczy - zaladuj to do grida hurtem, jako calosc, jedna gigantlista/tabela/array/.. do jego .datasource. oczywiiscie przy rozmiarze >N i tak bedzie lekko zgrzytac, ale ladowanie bedzie raz, a potem GUI bedzie responsywne


jezeli zas danych masz az tak duzo, ze faktyczne potrzebujesz virtual mode - to sluchaj nie tylko na cellvalueneeded ale takze na innych eventach zwiazanych z vmode. VMode/BGV i tak nie uratuje Cie przed zgrzytami w tym trybie, gdyz VMode NIE sluzy przyspieszaniu, a pomaganiu w NIE-trzymaniu ogromnej ilosci danych w pamieci. VMode bedzie Ciebie pytal o dane na biezaco, BGV bedzie musial skakac po plikach i wyszukiwac potrzebne dane, a Ty musisz to tak zorganizowac zeby ... obsluga eventow cellvalueneede/etc byla blyskawiczna. Im ja szybsza zrobisz, tym GUI bedzie szybsze. Czyli zadnego zlecania zadan i synchronicznego szukania w plikach na biezaco. Sam sobie robisz cache, predykcje i zlecanie zadan dla workera aby zgadnac gdzie jeszcze user moze chciec zaraz zajrzec. A w razie pudla, zlecenie zadania watkowi, pokazanie klepsydry userowi, callback z watku i update danych, wylaczenie klepsydry... W ladniejszej wersji: w razie pudla, zwrocenie napisow "ladowanie..." do wyswietlenia w komorkach grida, i asynchroniczna podmiana tych komorek jak juz dane beda dostepne..

do wyboru do koloru..

ah.. no i GridView IIRC mial jeszcze metody Begin/End/Edit/Update ktore WYlaczaja redraw na czas hurtowych modyfikacji danych..

0
quetzalcoatl napisał(a)

NIe pamietam za dobrze, ale VirtualMode odpytyje Cie za pomoca eventow tylko o te dane, ktore grid sadzi ze sa mu aktualnie potrzebne - czyli N komorek * M wierszy aktualnie widocznych +- jeden/kilka wierszy ekstra. On te dane na czas wyswietlania TYCH wierszy sobie zapamieta, i nie zapyta o nic, dopoki user nie ruszy scrollbarem itp.

Nie ma opcji "odpytywania Ciebie podczas rysowania danej komorki", ponieaz JESLI Ty byś podczas rysowania omorki byl pytany o dane i Ty bys zaślamazarzyl na sekunde czy pół, to dopiero współczuje prędkości Twojego GUI. Grid sie Ciebie zapyta co najwyzej w momencie, gdy przygotowuje sie do narysowania czegos..

Dokładnie to miałem na myśli, że odpyta ileś tam komórek, żeby wszystko wyglądało ok od strony Usera, a przy scrollowaniu będzie wołał resztę.


Jaki "binding" trwa dlugo? Na biezaco watek BGV wstawia wiersze? wiersz-po-wierszu? to sie nie dziwie ze Ci zgrzyta, same redrawy grida razy milion wierszy beda zgrzytac.. Zmien to na prace "paczkami" np. przenoszenie danych co 100, 1000 skonczonych wierszy, nie laduj pojedynczo - oszczedzisz na przerysowaniach.

Druga rzecz - JAK ladujesz dane do grida? Thread BGV poprzez invoke bezposrednio robi nowy wiersz w kontrolce? Jesli tak, zmien to natychmiast -chociazby- na uzycie BGV-reportprogress co wspomniane X wierszy, dodatkowo oszczedzisz na invoke. A w ogole - nie powinienes operowac na gridzie w ten sposob.. grid powienien miec jakies .DataSource ustawione na np. liste twoich wierszobiektow, BGV powinien nawalac wierszami (np. paczkami po 100/1000) do tej listy. zaleta jest taka, ze teraz mozesz to "rozpiąć", niech BGV nawala do listy tymczasowej, a jakis np. Timer co 0,5-3sek podmienia/skleja/(..) listy w gridzie<->tymczasowa.. Jezeli zas NIE potrzebujesz "animowanego"/"przyrostowego" ladowania grida, niech BGV przemieli sobie spokojnie wszystko, a dopiero jak skonczy - zaladuj to do grida hurtem, jako calosc, jedna gigantlista/tabela/array/.. do jego .datasource. oczywiiscie przy rozmiarze >N i tak bedzie lekko zgrzytac, ale ladowanie bedzie raz, a potem GUI bedzie responsywne

W BWT tworzę System.Data.DataTable i w BWThread_RunWorkerCompleted robię:

if (EventsTable != null)
            {
                if (DGVEvents.InvokeRequired)
                {
                    DGVEvents.BeginInvoke( new MethodInvoker( delegate(){ DisplayEvents(); } ));
                    return;
                }
                DGVEvents.DataSource = EventsTable;
                DGVEvents.Columns[0].Visible = false;
                DGVEvents.Columns[1].DefaultCellStyle.Format = "yyyy-MM-dd HH:mm:ss:ffff";
            }

jezeli zas danych masz az tak duzo, ze faktyczne potrzebujesz virtual mode - to sluchaj nie tylko na cellvalueneeded ale takze na innych eventach zwiazanych z vmode. VMode/BGV i tak nie uratuje Cie przed zgrzytami w tym trybie, gdyz VMode NIE sluzy przyspieszaniu, a pomaganiu w NIE-trzymaniu ogromnej ilosci danych w pamieci. VMode bedzie Ciebie pytal o dane na biezaco, BGV bedzie musial skakac po plikach i wyszukiwac potrzebne dane, a Ty musisz to tak zorganizowac zeby ... obsluga eventow cellvalueneede/etc byla blyskawiczna. Im ja szybsza zrobisz, tym GUI bedzie szybsze. Czyli zadnego zlecania zadan i synchronicznego szukania w plikach na biezaco. Sam sobie robisz cache, predykcje i zlecanie zadan dla workera aby zgadnac gdzie jeszcze user moze chciec zaraz zajrzec. A w razie pudla, zlecenie zadania watkowi, pokazanie klepsydry userowi, callback z watku i update danych, wylaczenie klepsydry... W ladniejszej wersji: w razie pudla, zwrocenie napisow "ladowanie..." do wyswietlenia w komorkach grida, i asynchroniczna podmiana tych komorek jak juz dane beda dostepne..

do wyboru do koloru..

ah.. no i GridView IIRC mial jeszcze metody Begin/End/Edit/Update ktore WYlaczaja redraw na czas hurtowych modyfikacji danych..

Próbowałem z suspend i resume Layout i parę innych rzeczy, ale problem pozostaje. Ostatecznie zrobię chyba jakiś paging.</quote>

0

w tym wypadku faktycznie, albo zostaje ostatnia opcja z "full featured" vmode, albo wlasnie paging.

@ begin/end/edit/update nie mialem na mysli begin/resumelayout -- gdyz one sa kompletnie od czegos innego - ale parę BeginUpdate i EndUpdate ktore (od)blok(ow)ują redraw kontrolki i sie swietnie nadaja do jej tymczasowego nie-rysowania gdy jest czyms ciężko zajęta. niestety w msdn dot. datagrid(view) nie widze ich, przepraszam, musialo mi sie pomylic np. z devexpress albo inna kontrolka.. moze listview, nie pamietam

1 użytkowników online, w tym zalogowanych: 0, gości: 1, botów: 0