dotaz ohledně vláken   zodpovězená otázka

VB.NET, WinForms

Dobrý den všem,

mám dotaz když procházím adresář a jeho obsah + nějaké další prkotiny zobrazuji v DGV a neudělám to v jiné vlákně tak můžu normálně obsah DGV rolovat posuvníkem. Jenomže aplikace po dobu načítání nereaguje a není to pěkné...

Pokud ale načtu obsah v jiném vlákně, posuvník nereaguje.

Ne že by mi to nějak extra vadilo ale setkal se tím někdo a vyřešil to?

Děkuji

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Něco děláte špatně. Uživatelské rozhraní (posuvník) nereaguje pouze pokud je zahlceno hlavní vlákno aplikace.

nahlásit spamnahlásit spam 0 odpovědětodpovědět

no právě... ale možná mi něco chybí... můžete se prosím mrknout? děkuji

 thread = New Threading.Thread(AddressOf nacti)
 thread.Start()

Private Sub nacti()
       
            Dim soubory = FileIO.FileSystem.GetFiles(My.Settings.Slozka_1, fileIO.SearchOption.SearchAllSubDirectories)
            ToolStripProgressBar1.Maximum = soubory.Count
            For i = 0 To soubory.Count - 1
                Dim f As New IO.FileInfo(soubory(i))
                DataGridView1.Rows.Add()
                Dim a = 1
                With DataGridView1.Rows(i)
                    .Cells(0).Value = a + i
                    .Cells(1).Value = TextBox1.Text.ToUpper
                    .Cells(2).Value = DateTimePicker1.Text
                    .Cells(3).Value = f.FullName
                    .Cells(4).Value = GetSHA1(f.FullName)
                    .Cells(5).Value = f.LastWriteTime
                End With

                ToolStripProgressBar1.Value = DataGridView1.Rows.Count
            Next

    End Sub
nahlásit spamnahlásit spam 0 odpovědětodpovědět

V momentě spuštění metody nacti musí už na řádku ToolStripProgressBar1.Maximum = soubory.Count dojít k vyjímce, protože přistupujete k ovládacím prvkům z jiného vlákna, než ze kterého byly vytvořeny.

Ve vlastním vlákně se provádí pouze náročný výpočet (hádám GetSHA1), aktualizace uživatelského rozhraní se musí provádět v hlavním vlákně.

Tady je o tom víc:

http://www.codeproject.com/Articles/9597...

Pokud se vám s tím nechce srát, použijte komponentu BackgroundWorker, ta má synchronizaci zabudovanou v sobě.

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Jak předávat data z worker threadu do hlavního vlákna a aktualizovat UI se tu řešilo již několikrát, například třeba zde:

http://www.dotnetportal.cz/forum/tema/23...

nahlásit spamnahlásit spam 0 odpovědětodpovědět

tak i s backgroundworkerem je situace stejná... po načtení DGV nejde posuvník uchopit

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Pokud není co posouvat, posuvník pochopitelně nebude fungovat. Stejně tak pokud se zakáže, nebo jeho nadřízený kontejner.

nahlásit spamnahlásit spam 0 odpovědětodpovědět

no když načtu asi 400 položek tak už posouvat je co... posuvníky zakázané nejsou... po načtení můžu rolovat jenom kolečkem na myši, uchopit posuvník nemůžu...

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Zkuste vytvořit nový projekt a do něj přidat DGV do kterého načíst pár stovek náhodných položek, jestli se to bude chovat stejně.

nahlásit spamnahlásit spam 0 odpovědětodpovědět

no pokud to neřeším pomocí vlaken tak se posuvník v dgv chová dobře... načte všechny položky a posuvník se dá normálně uchopit, jediné co tak aplikace samozřejmně zamrzne

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Vy ale plácáte totální hovadiny. Posuvník ani žádný jiný ovládací prvek nelze ovládat ani uchopit, pokud aplikace zamrzne z důvodu vytížení hlavního vlákna. Při jakémkoliv takovém pokusu se do titulkového pruhu přidá text (Neodpovídá).

nahlásit spamnahlásit spam 0 / 4 odpovědětodpovědět

neplácám hovadiny, kdybyste četl a pamatoval, ale chápu že toho máte v hlavě hodně... psal jsem že posuvník nejde uchopit a rolovat s ním v případě že načítam DGV v jiném vlákně a načítání skončí...

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Uveďte zde celý ten kód toho jak to načítáte a jak aktualizujete to UI.

nahlásit spamnahlásit spam 0 odpovědětodpovědět

kod je o pár odpovědí výše ...

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Měl jsem namysli upravený s tím BackgroundWorkerem nebo SynchronizationContextem. Ten kód nahoře fungovat nebude. Musíte oddělit práci na pozadí od aktualizace UI, protože aktualizaci UI musíte nechat provádět hlavní thread.

Já bych to konkrétně udělal tak, že worker bude vyrábět instance pomocné třídy, která přenese data pro jeden soubor (FullName, LastWriteTime, GetSHA1). S každou touto vyrobenou instancí bych pak přes událost a SynchronizationContext.Post notifikoval UI thread, který teprve provede přidání řádku do DGV a také aktualizaci progress baru.

To volání události by bylo úplně stejně jako to

this.SynchronizationContext.Post(_ => OnCompleted(), null);

v příkladu co jsem odkazoval výše (pouze se událost nebude volat jednou až na konci, ale několikrát v průběhu).

nahlásit spamnahlásit spam 0 odpovědětodpovědět

A už výše Vám pan Linhart řekl, že nelze z vedlejšího vlákna (ve vašem případě metoda nacti()) přistupovat k ovládacím prvkům hlavního vlákna.

Použijte BackgroundWorker.

BackgroundWorker má události:

DoWork - Zde si vykonáte načítání

ProgressChanged - Zde si budete upravovat UI

RunworkerCompleted - Zde si vrátíte data pro grid.

Ale pokud jsem správně pochopil, že chcete aby při načítání se zároveň aktualizoval progressbar i datagrid, tak jsem zkusil aktualizovat v progresschanged, přes parametr UserState a také to funguje. Jen je potřeba ověřovat dostupnost Ui prvků (při běžícím vlákně a ukončení aplikace).

Je to v C# ale s tím si poradíte.


       //Instance backgroundworkeru
       private readonly BackgroundWorker _bw;

        public Form1()
        {
            InitializeComponent();

            //inicializace backgrounworker
            _bw = new BackgroundWorker { WorkerReportsProgress = true };

            //události - do work je událost v jiném vlákně
            _bw.DoWork += Bw_DoWork;

            //progress changed událost mění hodnoty v hlavním vlákně
            _bw.ProgressChanged += BwProgressChanged;

        }

        //Pokud budete potřebovat do této metody dostat nějaká jiná data, 
        //tak jako parametr v RunWorkerAsync, já tam mám pouze seznam souborů
        void Bw_DoWork(object sender, DoWorkEventArgs e)
        {
            var worker = sender as BackgroundWorker;
            var soubory = e.Argument as List<string>;

            if (soubory == null || worker == null) return;

            for (var i = 0; i < soubory.Count; i++)
            {
                var fi = new System.IO.FileInfo(soubory[i]);

                //výstup pro datagrid předávám jako pole objektů
                var result = new object[]
                {
                    i+1,
                    "Nějaký text",
                    DateTime.Parse("12.3.2014"),
                    fi.FullName,
                    GetSha(fi.FullName),
                    DateTime.Now
                };

                worker.ReportProgress(i, result);
            }
        }
        
        //Dlouho trvající operace
        private string GetSha(string fileName)
        {
            var result = fileName.GetHashCode();
            System.Threading.Thread.Sleep(200);
            return result.ToString(CultureInfo.InvariantCulture);
        }

        //aktualizace ui a načítání do datagridu
        private void BwProgressChanged(object sender, ProgressChangedEventArgs e)
        {

            //ukončení vlákna, při ukončení aplikace
            if (progressBar1 == null || dataGridView1 == null)
            {
                _bw.CancelAsync();
                return;
            }
            
            progressBar1.Value = e.ProgressPercentage;
            dataGridView1.Rows.Add((object[])e.UserState);
        }

        //start úlohy
        private void button1_Click(object sender, EventArgs e)
        {
            if (_bw.IsBusy) return;
            var soubory = System.IO.Directory.GetFiles("C:\\Windows").ToList();
            progressBar1.Maximum = soubory.Count - 1;
            _bw.RunWorkerAsync(soubory);
        }

Jo a v datagridu musíte mít správný počet sloupců, jinak to spadne, ale na to by jste přišel.

nahlásit spamnahlásit spam 1 / 1 odpovědětodpovědět
                       
Nadpis:
Antispam: Komu se občas házejí perly?
Příspěvek bude publikován pod identitou   anonym.
  • Administrátoři si vyhrazují právo komentáře upravovat či mazat bez udání důvodu.
    Mazány budou zejména komentáře obsahující vulgarity nebo porušující pravidla publikování.
  • Pokud nejste zaregistrováni, Vaše IP adresa bude zveřejněna. Pokud s tímto nesouhlasíte, příspěvek neodesílejte.

přihlásit pomocí externího účtu

přihlásit pomocí jména a hesla

Uživatel:
Heslo:

zapomenuté heslo

 

založit nový uživatelský účet

zaregistrujte se

 
zavřít

Nahlásit spam

Opravdu chcete tento příspěvek nahlásit pro porušování pravidel fóra?

Nahlásit Zrušit

Chyba

zavřít

feedback