Dispatcher Invoke (…) vs BeginInvoke (…) confusione

Sono confuso perché non riesco a far funzionare questa controprova con 2 (o più) countertextbox in esecuzione simultanea con l’uso di “BeginInvoke” sul mio Dispatcher nel metodo Count ().

Puoi risolvere il problema sostituendo BeginInvoke con Invoke. Ma questo non risolve la mia confusione.

Ecco il codice di esempio di cui sto parlando:

public class CounterTextBox : TextBox { private int _number; public void Start() { (new Action(Count)).BeginInvoke(null, null); } private void Count() { while (true) { if (_number++ > 10000) _number = 0; this.Dispatcher.BeginInvoke(new Action(UpdateText), System.Windows.Threading.DispatcherPriority.Background, null); } } private void UpdateText() { this.Text = "" + _number; } } 

    Quando si utilizza Dispatcher.BeginInvoke significa che pianifica l’azione data per l’esecuzione nel thread dell’interfaccia utente in un momento successivo, quindi restituisce il controllo per consentire al thread corrente di continuare l’esecuzione. Invoke blocca il chiamante fino al termine dell’azione pianificata.

    Quando usi BeginInvoke tuo ciclo funzionerà in modo super veloce poiché BeginInvoke ritorna immediatamente. Ciò significa che stai aggiungendo molte e molte azioni alla coda dei messaggi. Li stai aggiungendo molto più velocemente di quanto possano essere effettivamente elaborati. Ciò significa che c’è molto tempo tra quando si pianifica un messaggio e quando si ha effettivamente la possibilità di essere eseguito.

    L’azione effettiva che stai utilizzando utilizza il campo _number . Ma _number viene modificato dall’altra thread molto rapidamente e mentre l’azione è in coda . Ciò significa che non mostrerà il valore di _number al momento in cui hai programmato l’azione, ma piuttosto che cosa è dopo che è proseguito nel suo ciclo molto stretto.

    Se invece usi Dispatcher.Invoke , impedisce al loop di “anticipare se stesso” e avere più eventi programmati, il che garantisce che il valore che sta scrivendo sia sempre il valore “corrente”. Inoltre, forzando ogni iterazione del ciclo per attendere che il messaggio venga eseguito, il loop diventa molto meno “stretto”, quindi non può essere eseguito in modo altrettanto rapido in generale.

    Se vuoi usare BeginInvoke la prima cosa che devi fare è rallentare il tuo ciclo. Se si desidera che aggiorni il testo ogni secondo, o sempre 10 ms o qualsiasi altra cosa, è ansible utilizzare Thread.Sleep per attendere il tempo appropriato.

    Successivamente, devi prendere una copia di _number prima di passarlo al Dispatcher modo che visualizzi il valore nel momento in cui lo hai programmato, non nel momento in cui viene eseguito:

     while (true) { if (_number++ > 10000) _number = 0; int copy = _number; this.Dispatcher.BeginInvoke(new Action(() => UpdateText(copy)) , System.Windows.Threading.DispatcherPriority.Background, null); Thread.Sleep(200); } 

     private void UpdateText(int number) { this.Text = number.ToString(); }