System.Windows.Threading.Dispatcher e WinForms?

System.Windows.Threading.Dispatcher funziona sul thread UI di un’applicazione WinForms ?

Se sì, perché? Viene da WindowsBase.dll che sembra essere un componente WPF .

In caso contrario, come posso richiamare le unità di lavoro sul thread dell’interfaccia utente? Ho trovato Control.BeginInvoke() , ma sembra maldestro creare un controllo solo per fare riferimento al thread di origine.

Puoi usare Dispatcher anche in un’app WinForms.

Se sei sicuro di essere su un thread dell’interfaccia utente (ad esempio in un pulsante. Gestisci il gestore), Dispatcher.CurrentDispatcher fornisce il dispatcher del thread dell’interfaccia utente che è ansible utilizzare in seguito per inviare dai thread in background al thread dell’interfaccia utente come di consueto.

Dispatcher è un componente WPF, non un componente WinForms.

Se si desidera inviare elementi di lavoro sul thread dell’interfaccia utente, è necessario utilizzare Control.BeginInvoke come già trovato o reactjs a ResetEvents / WaitObjects attraverso i thread.

Solitamente invocare elementi di lavoro sul thread dell’interfaccia utente è una cosa brutta a meno che non si tratti di un’interfaccia utente (ad esempio l’aggiornamento del contenuto di un controllo o qualcosa del genere), nel qual caso sarebbe sufficiente Control.BeginInvoke ().

Ho fornito un esempio di utilizzo di System.Windows.Threading.Dispatcher in Windows Form nella mia risposta alla domanda “Parallel Programming using TPL on WinForms” dalla precedente risposta alla tua domanda :

Se sei sicuro di essere nel thread dell’interfaccia utente (ad esempio in un pulsante. Gestisci il gestore), Dispatcher.CurrentDispatcher ti fornisce il dispatcher del thread dell’interfaccia utente che puoi utilizzare per inviare dal thread in background al thread dell’interfaccia utente come al solito.

è fuorviante o confusa o manca del contesto di utilizzo concreto:

  • button.Click handler non garantisce di essere sul thread UI;
  • se non si è sul thread dell’interfaccia utente, è ancora ansible utilizzare il disparcher del thread UI del modulo WinForms

Si può ottenere il dispatcher del thread dell’interfaccia utente di WinForm:

 Dispatcher dispatcherUI = Dispatcher.CurrentDispatcher; 

in qualsiasi gestore di eventi click su pulsante o altrove (nel costruttore di moduli)

E poi usalo per eseguire l’interfaccia utente da altri thread, vedi più dettagli nell’esempio qui sotto nella mia risposta :

 private void button1_Click(object sender, EventArgs e) { Dispatcher dispUI = Dispatcher.CurrentDispatcher; for (int i = 2; i < 20; i++) { int j = i; var t = Task.Factory.StartNew (() => { var result = SumRootN(j); dispUI.BeginInvoke (new Action (() => richTextBox1.Text += "root " + j.ToString() + " " + result.ToString() + Environment.NewLine ) , null ); } ); } 

Utilizza thread di lavoro in background poiché è in grado di rilevare messaggi di interfaccia utente, Questo articolo MSDN, sebbene in gran parte su WPF, afferma che BWT è in grado di riconoscere l’interfaccia utente anche per i moduli di Windows.

Ho avuto problemi simili usando la class di dipendenza Oracle che viene eseguita sul proprio thread all’interno di Winforms,

Quando l’evento OnChange è stato triggersto dalla dipendenza Oracle, volevo mostrare le modifiche in DataGridView semplicemente impostando DataSource su eventargs.Details (che è essenzialmente un DataTable) e lancia: System.InvalidOperationException non gestito dal codice utente Message = Operazione cross-thread non valido: Control ‘dataGridView1’ accessibile da un thread diverso dal thread su cui è stato creato.

L’utente di StackOverflow, Brian Peiris ([email protected]), il mio collega mi ha mostrato questo modo:

 void dep_OnChange(object sender, OracleNotificationEventArgs arg) { Console.WriteLine("Notification received"); int infoSum = int.Parse(arg.Details.Compute("Sum(Info)", "Info is not null").ToString()); InfoSum x = (InfoSum)infoSum; foreach (DataRow dr in arg.Details.Rows) { Console.WriteLine(string.Format("Operation(InfoSum)= {0}", Enum.GetName(typeof(InfoSum), x))); Console.WriteLine(string.Format("ontable={0} Rowid={1},info={2}", dr.Field("ResourceName"), dr.Field("rowid"), dr.Field("info"))); } // Following will throw cross-thread // dataGridView1.DataSource = arg.Details; // instead of line above use the following dataGridView1.BeginInvoke((Action)(()=>dataGridView1.DataSource = arg.Details)); IsNotified = true; } } 

Dai un’occhiata al backgrounder e verifica se soddisfa le tue esigenze.

A volte un componente Timer è utile e facile da configurare in WinForms, basta impostare il suo intervallo e quindi abilitarlo, quindi assicurarsi che la prima cosa che si fa nel suo gestore di eventi Tick sia disabilitare se stesso.

Penso che Timer esegua il codice in una sua discussione, quindi potrebbe essere necessario fare un BeginInvoke (chiamato sull’object WinForm [this]) per eseguire l’azione.

 private WebBrowserDocumentCompletedEventHandler handler; //need to make it a class field for the handler below (anonymous delegates seem to capture state at point of definition, so they can't capture their own reference) private string imageFilename; private bool exit; public void CaptureScreenshot(Uri address = null, string imageFilename = null, int msecDelay = 0, bool exit = false) { handler = (s, e) => { webBrowser.DocumentCompleted -= handler; //must do first this.imageFilename = imageFilename; this.exit = exit; timerScreenshot.Interval = (msecDelay > 0)? msecDelay : 1; timerScreenshot.Enabled = true; }; webBrowser.DocumentCompleted += handler; Go(address); //if address == null, will use URL from UI } private void timerScreenshot_Tick(object sender, EventArgs e) { timerScreenshot.Enabled = false; //must do first BeginInvoke((Action)(() => //Invoke at UI thread { //run in UI thread BringToFront(); Bitmap bitmap = webBrowser.GetScreenshot(); if (imageFilename == null) imageFilename = bitmap.ShowSaveFileDialog(); if (imageFilename != null) { Directory.CreateDirectory(Path.GetDirectoryName(Path.GetFullPath(imageFilename))); //create any parent directories needed bitmap.Save(imageFilename); } bitmap.Dispose(); //release bitmap resources if (exit) Close(); //this should close the app, since this is the main form }), null); } 

puoi vedere quanto sopra in azione sullo strumento WebCapture ( http://gallery.clipflair.net/WebCapture , codice sorgente all’indirizzo: http://ClipFlair.codeplex.com , vedi la cartella Strumenti / WebCapture) che cattura gli screenshot dai siti web. BTW, se vuoi chiamare l’eseguibile da riga di comando assicurati di andare su Proprietà del progetto e alla scheda Sicurezza distriggers la sicurezza ClickOnce (altrimenti non può accedere alla riga di comando)