ListView i BackgroundWorker

0

Czesc,
Probuje wczytac plik (150324 lini) do listview z podgladem postepu w progressbarze

 private void wczytajButton_Click(object sender, EventArgs e)
        {
            DialogResult result = openFileDialog1.ShowDialog();
            if (result == DialogResult.OK)
            {
                pathToFile = openFileDialog1.FileName;
                bgw.RunWorkerAsync();
            }
        }

        private void bgw_DoWork(object sender, EventArgs e)
        {            
            try
            {
                listView1.Items.Clear();
                listView2.Items.Clear();
                BackgroundWorker worker = sender as BackgroundWorker;
                FileStream fs = new FileStream(pathToFile, FileMode.Open, FileAccess.Read);
                {
                    using (TextReader sr = new StreamReader(fs))
                    {
                        progressBar1.Step = 1;
                        progressBar1.Minimum = 0;
                        progressBar1.Maximum = sr.ReadLine().Length;
                        int counter = 0;
                        string[] readText = File.ReadAllLines(pathToFile);
                        foreach (string s in readText)
                        {
                            ListViewItem lvi = new ListViewItem();
                            string[] data = s.Split('\t');                            
                            lvi.SubItems.Add(data[1]);
                            lvi.SubItems.Add(data[2]);
                            listView1.Items.Add(lvi);

                            counter++;
                            worker.ReportProgress(counter);
                            //System.Threading.Thread.Sleep(500);
                        }
                    }
                    fs.Dispose();              
                }
            }
            catch { }
        }

Okienku wyboru pliku to wczytania sie otwiera ale po wybraniu pliku nic sie nie dzieje. Co robie zle? Dzieki.

0

Sprawdzałeś w ogóle w Debuggerze czy Ci przechodzi program przez bgw_DoWork?

0

Poprawilem bo wywalal exception

 private void wczytajButton_Click(object sender, EventArgs e)
        {
            DialogResult result = openFileDialog1.ShowDialog();
            if (result == DialogResult.OK)
            {
                this.pathToFile = openFileDialog1.FileName;
                if (bgw.IsBusy != true)
                    bgw.RunWorkerAsync();
            }
        }

        private void bgw_DoWork(object sender, EventArgs e)
        {            
            try
            {
                BackgroundWorker worker = sender as BackgroundWorker;              
                FileStream fs = new FileStream(this.pathToFile, FileMode.Open, FileAccess.Read);
                {
                    using (TextReader sr = new StreamReader(fs))
                    {
                        SettingProgressBar(sr.ReadLine().Length);
      
                        int counter = 0;
                        string[] readText = File.ReadAllLines(this.pathToFile);
                        foreach (string s in readText)
                        {
                            
                            string[] data = s.Split('\t');
                            PopulatingListView(data);
                            counter++;
                            worker.ReportProgress(counter);
                            System.Threading.Thread.Sleep(200);
                        }
                    }
                    fs.Dispose();
                }
            }
            catch (Exception ee) 
            {                
                MessageBox.Show(ee.ToString());
            }
        }

        private void PopulatingListView(string[] array)
        {
            if (this.listView1.InvokeRequired)
                this.listView1.Invoke(new DelegateList(PopulatingListView), new object[] { array });
            else
            {
                ListViewItem lvi = new ListViewItem(array[0]);
                lvi.SubItems.Add(array[1]);
                lvi.SubItems.Add(array[2]);
                this.listView1.Items.Add(lvi);
            }
        }

Teraz inny problem bo progress bar zapelnia sie za szybko a listview sie zapetla. Czy to wina tego ze plik ma az 150 000 lini?

0

Co to znaczy, że Listview się zapętla?

Poza tym: sr.ReadLine().Length - to Ci pobierze jedną linię i weźmie jej długość. Chodziło Ci raczej o File.ReadLines(path).Count();

0

Przy malym pliku ok 20 lini wyswietla ok, tylko progress bar przerywa szybciej (np przy 70% napelnienia), a przy duzym pliku laduje sie on w nieskonczonosc a progress bar zaladowuje sie caly w kilka sekund

0
siararadek napisał(a):

Co to znaczy, że Listview się zapętla?

Poza tym: sr.ReadLine().Length - to Ci pobierze jedną linię i weźmie jej długość. Chodziło Ci raczej o File.ReadLines(path).Count();

Dokladnie tak pomoglo zamienienie na

SettingProgressBar(readText.Length); 
0
 BackgroundWorker worker = sender as BackgroundWorker;
                    int counter = 0;
                    foreach (ListViewItem item1 in listView1.Items) ///W TEJ LINI EXCEPTIOn
                    {
                        SettingProgressBar2(listView1.Items.Count);
                        PopulatingListView2(item1);
                        counter++;
                        worker.ReportProgress(counter);
                    }
                }

Jak sobie poradzic z problem ze wyrzuca mi exception Cross-Thread operation not valid: Control "listview1" accessed.....

0

Nie jestem pewien czy powinieneś używać ReadAllLines. Na MSDN piszą, że ta metoda od razu wczytuje cały plik do tablicy. W takim razie progress bar pokazuje tylko wpisywanie linii do Listview, co jest imo absurdalne. Przy ReadLines możesz przechodzić po kolekcji, zanim jest cała pobrana.

0
siararadek napisał(a):

Nie jestem pewien czy powinieneś używać ReadAllLines. Na MSDN piszą, że ta metoda od razu wczytuje cały plik do tablicy. W takim razie progress bar pokazuje tylko wpisywanie linii do Listview, co jest imo absurdalne. Przy ReadLines możesz przechodzić po kolekcji, zanim jest cała pobrana.

Tak jest google ale nie wiem jak uzyc tego Invoke w tym przypadku FOREACH

0
  1. Po co wczytywać 150 tys. linii na raz do pamięci?
  2. Jakim cudem umieścić 150 tys. linii w ListBoxie?
    Wątpię, aby ta kontrolka w ogóle była w stanie wyświetlić tyle danych, a nawet jeśli, to ładowanie zajmie ze 2 godziny. W tym przypadku lepszy byłby DataGridView, który można zwirtualizować i podawać mu dane dynamicznie. Oczywiście dane należy odczytywać z pliku porcjami, a nie na raz.
0

Mi wczytuje wszystkie linie. Zajmuje to ok 3 minuty

0

Ja myślę że wczytanie 100.000 linii do string[] to nie jest jeszcze taki wielki problem — jest to na pewno łatwiejsze i mniej błędogenne niż ładowanie po kawałku — ale gorzej z tym że każda linia jest osobno dodawana do listboksa, i do tego jest jeszcze fafnaście funkcji wywołanych z których każda potencjalnie może powodować odrysowanie formy.

Spróbuj przygotować tablicę itemów i dodać ją całą za jednym zamachem za pomocą listView1.Items.AddRange(). I bez żadnych "ReportProgress" w ciasnej pętli. Wtedy zmierz ile to będzie trwało.

Bo w tej chwili 99% czasu tracisz niepotrzebnie.

2

Zabierasz się do tego trochę na opak...

  1. @somekind ma rację, prawdopodobnie do tego lepszy byłby DataGridView (nie napisałeś jak mają wyglądać dane które wyświetlasz). A jeśli nie...
  2. This way -> http://www.codeproject.com/Articles/42229/Virtual-Mode-ListView

VirtualMode w ListViewie pozwala Ci udawać że jest w nim 12323489071 itemów bez torturowania go faktycznym wrzucaniem tych danych. W ten sposób, jeśli tego dobrze użyjesz możesz zredukować czas ładowania do mniej więcej... sekundy? (oczywiście dane możesz ładować z pliku w częściach zamiast wszystkie na raz, w ten sposób nawet pliki 4GB+ Ci niestraszne).

edit:
@Azarien - sam to chciałem napisać, ale da się jeszcze fajniej ;]

0
Azarien napisał(a):

Ja myślę że wczytanie 100.000 linii do string[] to nie jest jeszcze taki wielki problem — jest to na pewno łatwiejsze i mniej błędogenne niż ładowanie po kawałku — ale gorzej z tym że każda linia jest osobno dodawana do listboksa, i do tego jest jeszcze fafnaście funkcji wywołanych z których każda potencjalnie może powodować odrysowanie formy.

Spróbuj przygotować tablicę itemów i dodać ją całą za jednym zamachem za pomocą listView1.Items.AddRange(). I bez żadnych "ReportProgress" w ciasnej pętli. Wtedy zmierz ile to będzie trwało.

Bo w tej chwili 99% czasu tracisz niepotrzebnie.

No fakt widac jak listview jest rysowany non stop w trakcie wpisywania kazdej lini. Czy moglbys pokazac jak uzyc tego AddRange() ale tak aby w progress barze bylo widac progress?

0

Nie musisz używać AddRange(). Przed wstawianiem elementów wywołaj .BeginUpdate(), a po wstawieniu ich .EndUpdate(). Mimo wszystko lepiej będzie skorzystać z VirtualMode bez względu na to czy wczytasz cały plik do pamięci czy nie. Problem polega przede wszystkim na tym, że tworzysz wszystkie ListViewItem od razu. Samo wczytanie 5mb pliku tekstowego (150 tysięcy wierszy z trzema kolumnami) trwa u mnie 30ms, a dodanie ich do ListView ponad 3 sekundy.
Korzystając z VirtualMode potrzebne ListViewItem będziesz tworzyć na żądanie (po tyle, ile będzie ich widocznych na ekranie) i ewentualnie je cache'ować (do tego też jest gotowy mechanizm, wszystko masz o tym na MSDN).

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