blocco dell’interfaccia quando si tenta di aggiornare datagridview

Sto usando sotto il codice per copiare i file e impostare la colonna di stato su datagridview per informare l’utente che la connessione è triggers ma quando premo il pulsante per eseguire è il metodo freeze dell’interfaccia …

Ho cercato molto so che usando task.run(); non è ansible dato che non è incluso in .not 4 è una nuova funzionalità di .net 4.5 so anche che Task.Factory.StartNew(); può essere usato invece di usare task.run () ma ha un sacco di rischi come thread implicito e so che usare il threading esplicito è anche una buona scelta

Voglio un piccolo aiuto per andare avanti con il mio progetto e continuare ad imparare invece di essere impilato in quel punto noioso

 public void PatchUpdates() { try { foreach (DataGridViewRow OfficeListRow in DGV_OfficeList.Rows) { string OfficeIPAddress = OfficeListRow.Cells[3].Value.ToString(); foreach (DataGridViewRow FileListRow in DGV_FileList.Rows) { string SoruceFileNamePath = FileListRow.Cells[4].Value.ToString(); string DestinationFileNamePath = @"\\" + OfficeIPAddress + @"\usb1_1\test\" + Path.GetFileName(SoruceFileNamePath); //check if connection to remote server is available var vResult = CheckOffice(OfficeIPAddress); if (vResult == 1) { DGV_OfficeList[4, DGV_OfficeList.CurrentCell.RowIndex].Value = "Connected"; File.Copy(SoruceFileNamePath, DestinationFileNamePath, true); //copy files... } else if (vResult == 0) { DGV_OfficeList[4, DGV_OfficeList.CurrentCell.RowIndex].Value = "disconnected"; break; } } } } catch (Exception ex) { MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); } } 

controlla il codice dell’ufficio qui sotto

  public int CheckOffice(string _ipAddress) { int timeout = 120; string data = "PingTestData"; byte[] buffer = Encoding.ASCII.GetBytes(data); Ping PingSender = new Ping(); PingOptions options = new PingOptions(); options.DontFragment = true; PingReply reply = PingSender.Send(_ipAddress, timeout, buffer, options); if (reply.Status == IPStatus.Success) { return 1; } else { return 0; } } 

sotto come ho provato a fare thread ma che non risolverà il mio problema

 public void PatchUpdates() { try { foreach (DataGridViewRow OfficeListRow in DGV_OfficeList.Rows) { string OfficeIPAddress = OfficeListRow.Cells[2].Value.ToString(); foreach (DataGridViewRow FileListRow in DGV_FileList.Rows) { string SoruceFileNamePath = FileListRow.Cells[4].Value.ToString(); string DestinationFileNamePath = @"\\" + OfficeIPAddress + @"\usb1_1\test\" + Path.GetFileName(SoruceFileNamePath); Thread foregroundthread = new Thread(() => CheckOffice(OfficeIPAddress)); foregroundthread.Start(); //check if connection to remote server is available if (CheckOffice(OfficeIPAddress) == 1) { DGV_OfficeList[3, DGV_OfficeList.CurrentCell.RowIndex].Value = "Connected"; //file.copy(sorucefilenamepath, destinationfilenamepath, true); //copy files... } else if (CheckOffice(OfficeIPAddress) == 0) { DGV_OfficeList[3, DGV_OfficeList.CurrentCell.RowIndex].Value = "disconnected"; break; } } } } catch (Exception ex) { MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); } } 

Ho anche provato questo, ma come ho detto thask.run non è disponibile a dot net 4

  var task = Task.Run(() => { var result = CheckOffice(OfficeIPAddress); this.BeginInvoke((Action)(() => { if (result == 1) { DGV_OfficeList[4, DGV_OfficeList.CurrentCell.RowIndex].Value = "Connected"; //file.copy(sorucefilenamepath, destinationfilenamepath, true); //copy files... } else if (result == 0) { DGV_OfficeList[4, DGV_OfficeList.CurrentCell.RowIndex].Value = "disconnected"; } })); } ); 

————————————————– ——- Aggiornare —————————————— —————

  public void PatchUpdates() { try { foreach (DataGridViewRow OfficeListRow in DGV_OfficeList.Rows) { string OfficeIPAddress = OfficeListRow.Cells[3].Value.ToString(); int RowNum = OfficeListRow.Index; foreach (DataGridViewRow FileListRow in DGV_FileList.Rows) { string SoruceFileNamePath = FileListRow.Cells[4].Value.ToString(); //string DestinationFileNamePath = @"\\" + OfficeIPAddress + @"\usb1_1\test\" + Path.GetFileName(SoruceFileNamePath); string DestinationFileNamePath = @"F:\test\" + Path.GetFileName(SoruceFileNamePath); //TestPurpose Thread t2 = new Thread(new ThreadStart(() => { int vResult = CheckOffice(OfficeIPAddress); UpdateUI(vResult, RowNum, SoruceFileNamePath, DestinationFileNamePath, OfficeIPAddress); })); t2.Start(); } } } catch (Exception ex) { MessageBox.Show(ex.Message, "Error Message", MessageBoxButtons.OK, MessageBoxIcon.Error); } } 

Il metodo UpdateUI per aggiornare l’interfaccia utente …

  public void UpdateUI(int vResult, int RowNum, string SoruceFileNamePath, string DestinationFileNamePath,string OfficeIPAddress) { try { var timeNow = DateTime.Now; if ((DateTime.Now - PreviousTime).Milliseconds  { if (vResult == 1) { DGV_OfficeList[4, RowNum].Value = "Connected"; //File.Copy(SoruceFileNamePath, DestinationFileNamePath, true); //MessageBox.Show("Pingable " + OfficeIPAddress); //TestPurpose } else if (vResult == 0) { DGV_OfficeList[4, RowNum].Value = "Disconnected"; //MessageBox.Show("Not reachable"); //TestPurpose } }), vResult); PreviousTime = timeNow; } catch (Exception ex) { MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); } } 

inserisci la descrizione dell'immagine qui

inserisci la descrizione dell'immagine qui

Risposta breve: non c’è niente di sbagliato nel tuo codice. Il design non è buono.

Risposta lunga

Hai sentito qualcuno dire “Posso fare solo una cosa alla volta!” Bene, questo è quello che sta succedendo qui. Il codice dell’applicazione Windows Form viene eseguito da 1 thread e quel thread può eseguire solo una cosa alla volta. Quando esegue il ping, attende la risposta. Se la risposta ha esito positivo, copia un file. Dato che hai un ciclo continua a farlo finché non ha completato tutte le righe.

Mentre lo fa, probabilmente stai facendo clic su altre cose nell’interfaccia utente, ma il tuo thread “può fare solo 1 cosa alla volta”. È impegnato a fare le cose nel giro. Pertanto, quando fai clic, devi solo aspettare.

Quindi, come posso risolvere il problema in modo che l’interfaccia utente non si blocchi?

In parole povere, devi farlo. Immagina di essere un filo:

Sono il thread dell’interfaccia utente e il mio objective finale è mantenere l’interfaccia utente retriggers. Non voglio che l’interfaccia utente si blocchi. Pertanto, se ho bisogno di fare qualsiasi cosa tranne l’interfaccia utente, ho intenzione di chiedere a qualcun altro di farlo. Mentre qualcun altro sta facendo altro lavoro, sarò libero di fare il lavoro dell’interfaccia utente.

Quel qualcun altro è un altro thread. Ecco un esempio, leggi i miei commenti nel codice e applicalo alla tua applicazione. Se si desidera eseguire questo codice, creare un modulo Form1 con un’etichetta denominata label1 e due pulsanti. Assegna ButtonClickHandlerAsync al gestore di clic di un pulsante e Stop_Click all’altro pulsante.

L’intera azione inizia quando si fa clic sul pulsante che esegue ButtonClickHandlerAsync . Mentre sta funzionando, puoi fare clic sull’altro pulsante e mostrerà una finestra di messaggio e manterrai la risposta. Dal modo in cui ho copiato questo codice da qui, ma ho aggiunto i miei commenti all’interno del codice in modo da sapere cosa sta succedendo.

 public partial class Form1 : Form { // We need this because this will allow us to interact with UI controls. UI controls can only be accessed by the thread that // created the UI control. In this case it is the thread which started the application so the main thread. private readonly SynchronizationContext synchronizationContext; private DateTime previousTime = DateTime.Now; public Form1() { InitializeComponent(); synchronizationContext = SynchronizationContext.Current; } private void Stop_Click(object sender, EventArgs e) { // I am the UI thread. I can do this because T2 is helping me do the loop. MessageBox.Show( "I am doing other things." ); } private async void ButtonClickHandlerAsync(object sender, EventArgs e) { button1.Enabled = false; var count = 0; // I am the UI thread. I have other things to do. So please run this loop by using a thread from the thread pool. // When you are done running the loop let me know (This is what the await does) // I am the UI thread so I am going to return back from right here // to the point where ButtonClickHandlerAsync was called from. (it was called by a click, so when it returns it will have nothing // to do. Therefore, it will be ready to react to another UI job such as another click or update the UI etc. await Task.Run( () => { // I am a thread from the thread pool. My name is T2. I am helping the UI thread so the UI thread can do other things. for( var i = 0; i < = 5000000; i++ ) { UpdateUI( i ); count = i; } } ); // I am the UI thread. Ok looks like the loop is done. So I will do the following 2 lines of work label1.Text = @"Counter " + count; button1.Enabled = true; } public void UpdateUI(int value) { // I am T2. I am helping the UI thread. var timeNow = DateTime.Now; if( ( DateTime.Now - previousTime ).Milliseconds <= 50 ) return; // I do not have access to the UI controls since I did not create them. So I am just going to ask the synchronizationContext // to do this for me by giving it a SendOrPostCallback synchronizationContext.Post( new SendOrPostCallback( o => { // I am the UI thread. I will do this. label1.Text = @"Counter " + ( int ) o; } ), value ); // I am T2. I will do this and then return and do more work. previousTime = timeNow; } 

Come puoi risolvere il tuo codice?

Puoi fare CheckOffice e copiare i file usando un thread dal threadpool. Quel thread può utilizzare synchronizationContext se deve interagire con l’interfaccia utente. Il thread principale dell’interfaccia utente può rimanere libero di fare altre cose mentre il thread dal pool di thread sta controllando l’ufficio e sta copiando un file che potrebbe richiedere molto tempo, soprattutto se il file è grande.

“Sono il thread dell’interfaccia utente, non ho tempo per aspettare una risposta ping.” “Io sono il thread dell’interfaccia utente, non ho tempo per copiare un file da una posizione a un’altra posizione che può richiedere secondi o minuti. Il mio compito è di mantenere l’interfaccia utente retriggers.”

MODIFICARE

Ho scritto la risposta di cui sopra prima che l’OP abbia scritto la restrizione di .NET 4. Ma sono abbastanza sicuro che abbiano creato un pacchetto NuGet per questo. Vedi qui e qui .

Se non puoi usare async e await , gli stessi concetti sopra si applicano al threading.

 Thread t2 = new Thread( new ThreadStart(() => { for( var i = 0; i < = 5000000; i++ ) { UpdateUI( i ); count = i; } } ) ); t2.Start();