PDA

View Full Version : [C#] Incrementare una ProgressBar da un altro Thread


qwerty_race
22-01-2021, 09:32
Buongiorno,
ho fatto un programmino in "Win Form" con Visual Studio 2019.

Questo programmino posta sui gruppi Facebook tramite "Selenium + Chrome Driver", quindi apre un Browser e simula tutti i passaggi umani.

Ho fatto il "Form1" quindi l'interfaccia utente dove si realizza il post e si seleziona i gruppi dove postare,
attraverso un nuovo Thread avvio una nuova istanza di "Chrome Driver", quindi mi si apre il browser e inizia tutte le procedure, login, post, etc...

Tra i vari controlli ho una ProgressBar alla quale non riesco ad applicare l'avanzamento dall'altro Thread,
ho letto la guida ufficiale MSN ma la struttura del mio programma non è come nell'esempio e non riesco ad interpretarla per me.

la mia struttura è cosi:

Form1:
Interfaccia Utente, dove c'è la ProgressBar.


private Browser oBrowser = new Browser();


public Form1()
{
InitializeComponent();
}


private void BtnLogin_Click(object sender, EventArgs e)
{
th = new Thread(new ThreadStart(Login))
{
ApartmentState = ApartmentState.STA
};
th.Start();
}


private void Login()
{
//Apro il Browser
oBrowser.OpenBrowser(wbHidden);

//Faccio Login su Facebook
if (oBrowser.Login(txtUser.Text, txtPass.Text))
{
//Controllo se sono loggato
if (!oBrowser.CheckLogin())
{
MessageBox.Show("Username o Password sbagliati", "Attenzione!", MessageBoxButtons.OK, MessageBoxIcon.Warning);
}
else
{
//Login effettuato
}
}
}


La mia Classe Browser dove devo incrementare la mia ProgressBar

class Browser : File
{
public bool Login(string _username, string _password)
{
//codice .....

myProgBar.PerformStep();

//codice .....

myProgBar.PerformStep();

//codice .....

myProgBar.PerformStep();
}
}


Potreste darmi una mano per vedere se riesco?

Vi ringrazio molto.

antonio338
25-01-2021, 21:52
Devi chiamare Invoke dal controllo che è ospitato nel thread della UI.
Questo dalla documentazione ufficiale: https://docs.microsoft.com/it-it/dotnet/api/system.windows.forms.control.invoke?view=net-5.0

Da dove arriva Invoke? E' presente nella classe Control che tutti i controlli di Winforms implementano.
Prendendo il tuo codice quindi diventerebbe:
myProgBar.Invoke(delegato)
dove delegato è un metodo che non ha argomenti e restituisce void.
Possiamo usare un delegato anonimo, facendo il cast su MethodInvoker che è un delegato che corrisponde al nostro caso.
myProgBar.Invoke((MethodInvoker) delegate {myProgBar.PerformStep(); })
Se hai molti metodi che devono essere eseguiti però diventa più mantenibile esporre dei metodi pubblici dal form che ospita i controlli, ipotizzando che myProgBar sia in Form1 potresti aggiungere:

public void DoProgress()
{
if (InvokeRequired)
{
Invoke((MethodInvoker)delegate{ myProgBar.PerformStep();});
}
else
{
myProgBar.PerformStep();
}
}

Cosi facendo però devi ripetere questo codice per ogni controllo che necessità di Invoke.
Come risolvere? Usando un metodo di estensione, la cui documentazione è cui:
https://docs.microsoft.com/it-it/dotnet/csharp/programming-guide/classes-and-structs/extension-methods
Il tuo metodo di estensione sarà molto simile all'esempio precedente:

static public void SafeExecute(this Control control, Action codice)
{
if (control.InvokeRequired)
{
control.Invoke(codice);
}
else
{
codice();
}
}

Quindi in fin dei conti potrai eseguire solo:
myProgBar.SafeExecute(() => myProgBar.PerformStep());
Ricorda che per vedere i metodi di estensione dall'Intellisense devi esplicitamente importare lo spazio dei nomi dove è contenuto