Visualizzazione dei risultati da 1 a 10 su 10
  1. #1
    Utente di HTML.it L'avatar di Veronica80
    Registrato dal
    May 2006
    Messaggi
    2,117

    [VB.NET] - Backgroundworkers

    Come da titolo sto provando a usare questi oggetti a me ancora sconosciuti!
    Ho letto più che potevo in giro a riguardo ma tempo di non averci capito nulla...

    Per ora ho creato un piccolo progetto di prova che non fa altro che creare a runtime una serie di textbox (così da stressare il lettore di codice) e che infatti blocca l'applicazione per alcuni secondi durante la creazione.

    Per testare il mio backgroundworker l'ho aggiunto alla mia form dal pannello oggetti (chiamandolo mioBGW) e ho buttato giù sto codice:

    codice:
        Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
            mioBGW.RunWorkerAsync()
        End Sub
    
        Private Sub mioBGW_DoWork(ByVal sender As System.Object, ByVal e As System.ComponentModel.DoWorkEventArgs) Handles mioBGW.DoWork
            Try
                Dim y As Integer = 3
                Dim max As Integer = 500
                For i = 1 To max
                    Dim mioTxt As New TextBox
                    mioTxt.Location = New System.Drawing.Point(3, y)
                    mioTxt.Name = "TextBox" & i
                    mioTxt.Text = mioTxt.Name
                    mioTxt.Size = New System.Drawing.Size(224, 20)
                    mioTxt.TabIndex = i
                    mioTxt.Visible = True
                    y += 25
                    Panel1.Controls.Add(mioTxt)
                Next
            Catch ex As Exception
                MsgBox(ex.Message, MsgBoxStyle.Critical, "Errore in " & ex.Source)
                mioBGW.CancelAsync()
            End Try
        End Sub
    
        Private Sub mioBGW_RunWorkerCompleted(ByVal sender As Object, ByVal e As System.ComponentModel.RunWorkerCompletedEventArgs) Handles mioBGW.RunWorkerCompleted
            MsgBox("FINITO!", MsgBoxStyle.Information, "Conferma")
        End Sub
    Però credo che non sia molto corretto
    Tant'è che mi da errore:

    Operazione cross-thread non valida: è stato eseguito l'accesso al controllo 'Panel1' da un thread diverso da quello da cui è stata eseguita la creazione.

    Credo di non aver capito proprio niente...non esiste una guida in italiano su questi oggetti? L'MSDN non mi è stato molto d'aiuto...oppure se qualcuno può spiegarmi un po dove sbaglio...

    Grazie come sempre!

  2. #2
    Utente di HTML.it L'avatar di oregon
    Registrato dal
    Jul 2005
    residenza
    Roma
    Messaggi
    36,480
    E' uno dei problemi più affrontati e discussi su internet ...

    Leggi

    http://msdn.microsoft.com/it-it/library/ms171728(v=vs.80).aspx

    per come affrontare correttamente la questione multithreading senza avere quell'errore.

    (In particolare "Eseguire chiamate thread-safe tramite BackgroundWorker")
    No MP tecnici (non rispondo nemmeno!), usa il forum.

  3. #3
    Confermo che i BW non sono molto documentati.

    Panel1 lo hai creato nel Thread principale, per cui mioBGW non lo "conosce" nella Sub DoWork, che "lavora" appunto su un altro thread.

    Quando usi un BW devi quindi creare una variabile a livello di classe, così che sia riconosciuta anche nel Thread del BW e poi mettere i controlli da aggiornare in RunWorkerCompleted (che è una Sub del thread principale), dove li modificherai in base alla variabile modificata nel Thread del BW.

    Spero di essere stato un minimo comprensibile...

  4. #4
    Utente di HTML.it L'avatar di Veronica80
    Registrato dal
    May 2006
    Messaggi
    2,117
    ahah oddio...non proprio! O meglio non so bene come fare quello che hai detto anche se in teoria pare l'abbia capito! :P

    Ora do uno sguardo al link che mi ha dato Oregon nella speranza mi si accenda la lampadina!

  5. #5
    Utente di HTML.it L'avatar di Veronica80
    Registrato dal
    May 2006
    Messaggi
    2,117
    niente non ne vengo a capo! E' davvero molto complessa la questione

  6. #6
    Utente di HTML.it L'avatar di Vinsent
    Registrato dal
    May 2011
    Messaggi
    314
    Originariamente inviato da Veronica80
    niente non ne vengo a capo! E' davvero molto complessa la questione
    Io ci sono arrivato con una soluzione diversa da quella di Eziogsv anche se devo ancora approfondire i "concetti"...quindi posto il tuo codice con le "modifiche" per farlo funzionare ed evito spiegazioni su Delegate e Invoke per non scrivere probabili razzate ...

    codice:
        'modifica
        Delegate Sub panel1_add(ByVal tbox As TextBox)
    
        Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
            mioBGW.RunWorkerAsync()
        End Sub
    
        Private Sub mioBGW_DoWork(ByVal sender As System.Object, ByVal e As System.ComponentModel.DoWorkEventArgs) Handles mioBGW.DoWork
            Try
                Dim y As Integer = 3
                Dim max As Integer = 500
                For i = 1 To max
                    Dim mioTxt As New TextBox
                    mioTxt.Location = New System.Drawing.Point(3, y)
                    mioTxt.Name = "TextBox" & i
                    mioTxt.Text = mioTxt.Name
                    mioTxt.Size = New System.Drawing.Size(224, 20)
                    mioTxt.TabIndex = i
                    mioTxt.Visible = True
                    y += 25
    
                    'modifica
                    panel1_add_tbox_deleg(mioTxt)
    
                Next
            Catch ex As Exception
                MsgBox(ex.Message, MsgBoxStyle.Critical, "Errore in " & ex.Source)
                mioBGW.CancelAsync()
            End Try
        End Sub
    
        Private Sub mioBGW_RunWorkerCompleted(ByVal sender As Object, ByVal e As System.ComponentModel.RunWorkerCompletedEventArgs) Handles mioBGW.RunWorkerCompleted
            MsgBox("FINITO!", MsgBoxStyle.Information, "Conferma")
        End Sub
    
        'modifica
        Private Sub panel1_add_tbox(ByVal tbox As TextBox)
            Panel1.Controls.Add(tbox)
        End Sub
    
        'modifica
        Private Sub panel1_add_tbox_deleg(ByVal tbox As TextBox)
            Dim a As New panel1_add(AddressOf panel1_add_tbox)
            Invoke(a, New Object() {tbox})
        End Sub
    Oltre al link a msdn postato da Oregon puoi dare una lettura a questo:
    http://msdn.microsoft.com/it-it/library/ms172879.aspx
    e le relative procedure per provare a chiarirti le idee.

  7. #7
    Utente di HTML.it L'avatar di Veronica80
    Registrato dal
    May 2006
    Messaggi
    2,117
    MA TU SEI UN ANGELOOO!

    Grazie mille! Ora mi documento meglio su tutte le modifiche che hai apportato!

    Forse chiedo troppo ma avresti anche un esempio su come ottenere il progresso del worker? Così metto pure una bella progressbar e sono all'apoteosi della gioia!

  8. #8
    Tieni presente comunque che non ha molto senso fare un backgroundworker se deve continuamente interagire con l'interfaccia e quindi sincronizzarsi con il thread principale. L'idea di fondo è che un backgroundworker fa un lavoro che prosegue indipendentemente da quello che fa l'interfaccia (che so, fa dei conti, attende l'esito di operazioni di IO, ...), sincronizzandosi giusto per riportare l'avanzamento dell'operazione.

    Il problema di fondo infatti è che il backgroundworker lavora in un thread separato, e gli oggetti Windows Forms non sono thread-safe (ovvero, sono pensati per essere gestiti solo dal thread in cui gira il message loop); per questo motivo, se il backgroundworker (o in generale un qualunque altro thread) vuole interagire con l'interfaccia deve usare Control.Invoke (chiamato sul form su cui vuole interagire), in modo che il delegate che chiama venga richiamato nel contesto del thread che gestisce la grafica. Questo però ovviamente richiede una sincronizzazione tra i due thread, per cui se tutto il lavoro che viene fatto dal backgroundworker necessita della Invoke si perde tutto il vantaggio di avere un thread separato.
    Amaro C++, il gusto pieno dell'undefined behavior.

  9. #9
    Utente di HTML.it L'avatar di Vinsent
    Registrato dal
    May 2011
    Messaggi
    314
    Originariamente inviato da Veronica80
    Forse chiedo troppo ma avresti anche un esempio su come ottenere il progresso del worker? Così metto pure una bella progressbar e sono all'apoteosi della gioia!
    ni...nel senso che leggendo qui:
    http://msdn.microsoft.com/it-it/libr...undworker.aspx
    ho aggiunto una label con la percentuale e la progressbar ma ho dovuto rallentare il ciclo con 'Thread.Sleep' perchè altrimenti la label mostra il 100% e appare il msgbox ma la progressbar rimane "indietro"...

    codice:
    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
            'modifica
            ProgressBar1.Maximum = 100
            mioBGW.WorkerReportsProgress = True
    
            mioBGW.RunWorkerAsync()
        End Sub
    
        'modifica
        Private Sub bw_ProgressChanged(ByVal sender As Object, ByVal e As System.ComponentModel.ProgressChangedEventArgs) Handles mioBGW.ProgressChanged
            ProgressBar1.Value = e.ProgressPercentage
            Label1.Text = (e.ProgressPercentage.ToString() & "%")
        End Sub
    
        Private Sub mioBGW_DoWork(ByVal sender As System.Object, ByVal e As System.ComponentModel.DoWorkEventArgs) Handles mioBGW.DoWork
            Try
                'modifica
                Dim percentuale As Integer
    
                Dim y As Integer = 3
                Dim max As Integer = 500
                For i = 1 To max
                    Dim mioTxt As New TextBox
                    mioTxt.Location = New System.Drawing.Point(3, y)
                    mioTxt.Name = "TextBox" & i
                    mioTxt.Text = mioTxt.Name
                    mioTxt.Size = New System.Drawing.Size(224, 20)
                    mioTxt.TabIndex = i
                    mioTxt.Visible = True
                    y += 25
                    panel1_add_tbox_deleg(mioTxt)
    
                    'modifica
                    If (percentuale < CSng(i / max * 100)) Then
                        percentuale = CSng(i / max * 100)
                        mioBGW.ReportProgress(percentuale)
                    End If
                    Thread.Sleep(20)
    
                Next
            Catch ex As Exception
                MsgBox(ex.Message, MsgBoxStyle.Critical, "Errore in " & ex.Source)
                mioBGW.CancelAsync()
            End Try
        End Sub

  10. #10
    Utente di HTML.it L'avatar di Veronica80
    Registrato dal
    May 2006
    Messaggi
    2,117
    MItaly ho capito che intendi ma il problema è che se io lavoro sul mio thread si blocca il form e non è una cosa molto carina...Cioè quando devo creare un numero di controlli a runtime elevato vorrei almeno mettere una barra di progresso perchè se il programma ci mette molto uno non sa mai di che morte deve morire!

    Vinsent appena arrivo a casa provo subito il codice e vedo un po grazie 10000

Permessi di invio

  • Non puoi inserire discussioni
  • Non puoi inserire repliche
  • Non puoi inserire allegati
  • Non puoi modificare i tuoi messaggi
  •  
Powered by vBulletin® Version 4.2.1
Copyright © 2025 vBulletin Solutions, Inc. All rights reserved.