2009-07-14 9 views
14

Tendo ad usare StatusStrip nella parte inferiore della maggior parte delle mie applicazioni per semplici aggiornamenti di stato e occasionalmente una barra di avanzamento.Come si effettuano chiamate cross-threaded a ToolStripStatusLabel?

Tuttavia, sembra che ToolStripStatusLabels non erediti dal controllo, quindi non hanno .Invoke o .InvokeRequired. Quindi, come faccio a fare una chiamata thread-safe per cambiare la sua proprietà text?

risposte codificati per i posteri e altri che vengono alla ricerca:

Action<string> test=(text) => 
      { 
       if (this._statusStrip.InvokeRequired) this._statusStrip.Invoke(
       new MethodInvoker(() => this._lblStatus.Text = text)); 
       else this._lblStatus.Text = text; 
      }; 

o

private void TestInvoker(string text) 
    { 
     if (this._statusStrip.InvokeRequired) 
      this._statusStrip.Invoke(
        new MethodInvoker(() => this._lblStatus.Text = text)); 
     else this._lblStatus.Text = text; 
    } 
+0

@Maslow: Prestare attenzione nella logica intorno Control.Invoke.Le regole esposte nei documenti sono sottili e soggette a errori se non vengono lette attentamente. Per favore controlla il codice che ho nel link nella mia risposta per un uso più corretto di Invoke. Ad esempio, la tua implementazione non sta verificando che 'ToolStrip' non sia stato eliminato e non sta verificando che l'handle di' ToolStrip' sia stato creato. –

+0

A parte il fatto che l'handle non è ancora stato creato, sembra che questi casi non facciano altro che generare eccezioni se si verificano comunque, giusto? E se l'handle non è ancora stato creato, non sono sicuro che sia utile fingere che non sia successo nulla e non lanciare un'eccezione. – Maslow

risposta

27

Questa è una buona domanda!

Mentre il ToolStripStatusLabel non eredita dal controllo, lo ToolStrip contiene! Utilizzare l'Invoke di ToolStrip per effettuare chiamate contro lo ToolStripStatusLabel.

Questo perché ToolStrip gestisce manualmente il disegno dei suoi componenti, così come WPF gestisce il disegno di tutti i dei suoi bit componente, senza generare un handle separato per ciascuno. Ciò è utile perché è facile dimenticare che ogni HANDLE è associato al numero e che il sistema ha solo un numero finito, ad esempio

(Ho già avuto modo di farlo prima. barra laterale sulla another question, per esempio. ho dovrebbe aggiornare il testo in modo da riflettere la mia comprensione più recente.)

+1

Sì, e si potrebbe anche utilizzare il metodo Forms Invoke poiché viene creato sullo stesso thread. Ma vorrei andare con la soluzione di Greg D come è più logico. –

+0

@sindre, non necessariamente, ma probabilmente ... mentre i ToolStripStatusLabels sono necessariamente creati sullo stesso thread di StatusStrip –

2

Inoltre, in generale, non è Avere per usare l'InvokeRequired e BeginInvoke sulla esattamente lo stesso controllo che si manipolano il codice, purché tu possa garantire che il controllo che stai manipolando sia stato creato sullo stesso thread (ad esempio, nell'inizializzazione dei moduli routine di ioni), come l'elemento dell'interfaccia utente che si chiama InvokeRequired/BeginInvoke.

+0

ah dettagli interessanti – Maslow

0

È possibile eseguire questa operazione utilizzando la parola chiave delegate e il metodo Control.Invoke(). Questo esempio mostra come gestisci un thread safe .Text e .FunzionaloreColore.

private delegate void SetToolStripDelegate(string text, Color color); 

private void SetToolStrip(string text, Color color) 
{ 
    statusBar.Text = text; 
    statusBar.ForeColor = color; 
} 

All'interno del contesto del thread è possibile effettuare una chiamata di thread-safe di questo metodo come questo:

{ // thread begin... 

    // somewhere inside the thread 
    Invoke(new SetToolStripDelegate(SetToolStrip), "Connected.", Color.Green); 

} // thread end... 
0

In parole semplici, passando Elementi StatusStrip, passare il StatusStrip troppo lungo nel parametro e utilizzare come metodo StatusStrip.BeginInvoke o Invoke e posizionare gli elementi della barra di stato al suo interno.

Il codice riportato di seguito dovrebbe aiutare come chiamare e aggiornare StatusStrip non solo da altre attività/thread, ma anche da un'altra classe.

//Coded by Chandraprakash [2017-07-18] 
//frozenprakash.com 

using System; 
using System.Threading; 
using System.Threading.Tasks; 
using System.Windows.Forms; 

namespace UIUpdateFromOtherClass 
{ 

public partial class Form1 : Form 
{ 
    public Form1() 
    { 
     InitializeComponent(); 
    } 

    private void button1_Click(object sender, EventArgs e) 
    { 
     FN_Execute(); 
    } 

    async void FN_Execute() 
    { 
     Second s = new Second(); 
     await Task.Run(() => s.Execute(lbl1, 
             pb1, 
             ss1, 
             ss1Lbl1, 
             ss1Pb1) 
         ); 
     MessageBox.Show("End"); 
    } 

} 

public class Second 
{ 
    public void Execute(Label lbl1, 
         ProgressBar pb1, 

         StatusStrip ss1, 
         ToolStripLabel tsLbl1, 
         ToolStripProgressBar tsPb1) 
    { 
     lbl1.BeginInvoke(new Action(() => 
      lbl1.Text = "Second" 
     )); 

     pb1.BeginInvoke(new Action(() => 
     { 
      pb1.Style = ProgressBarStyle.Marquee; 
      pb1.MarqueeAnimationSpeed = 10; 
     })); 

     ss1.BeginInvoke(new Action(() => 
     { 
      tsLbl1.Text = "Second"; 

      tsPb1.Style = ProgressBarStyle.Marquee; 
      tsPb1.MarqueeAnimationSpeed = 10; 
     })); 

     Thread.Sleep(3000); 
    } 
} 

} 

Windows Forms Screenshot

Problemi correlati