2017-01-10 1 views
0

J'ai besoin d'aide avec BackgroundWorker. Utilisation de Visual Studio 2015 et ses formulaires WindowsTextBox non mis à jour en temps réel via BackgroundWorker avec DataReceivedEventHandler activé

Je suis nouveau à ce genre de choses et je n'ai vraiment aucune idée de comment cela fonctionne, etc. Le code que j'ai jusqu'ici est basé sur divers messages ici.

worker_DoWork_ ne pas être déclenché du tout, mais aucune idée pourquoi. Je crois que c'est quelque chose à voir avec DataRceivedEventHandler parce que quand je déplace le If je déplace le worker.DoWork + = worker_DoWork_; et worker.RunWorkerAsync(); en événement cliqué sur un bouton et désactiver DataReceivedEventHandler, la méthode worker_DoWork_ est déclenchée et je peux mettre à jour textBox avec n'importe quel texte statique affecté sous DoSomeWork.

Aussi, je ne sais pas comment passer des données de plan dans la zone de texte via DoSomeWork.

Quelqu'un peut-il vous aider s'il vous plaît.

using System; 
using System.Collections.Generic; 
using System.ComponentModel; 
using System.Data; 
using System.Drawing; 
using System.Linq; 
using System.Text; 
using System.Threading.Tasks; 
using System.Windows.Forms; 
using System.Diagnostics; 
using System.Threading; 


namespace CMD_testing 
{ 
    public partial class Form1 : Form 
    { 
    BackgroundWorker worker; 
    private delegate void DELEGATE(); 

    public Form1() 
    { 
     InitializeComponent(); 
     worker = new BackgroundWorker(); 
    } 

    private void button2_Click(object sender, EventArgs e) 
    { 

     Process process; 
     process = new Process(); 
     process.StartInfo.FileName = @"C:\\Project\Test\Data.bat"; 
     process.StartInfo.UseShellExecute = false; 
     // process.StartInfo.CreateNoWindow = true; 
     process.StartInfo.RedirectStandardOutput = true; 
     process.OutputDataReceived += new DataReceivedEventHandler(OutputHandler); 

     process.StartInfo.RedirectStandardInput = true; 
     process.Start(); 
     process.BeginOutputReadLine(); 
     // process.WaitForExit(); 
     // process.Close(); 
    } 

    private void OutputHandler(object sendingProcess, DataReceivedEventArgs outLine) 
    { 
     if (outLine.Data != null) 
     { 
      Console.WriteLine("Im here..."); 

      worker.DoWork += worker_DoWork_; 
      //worker.RunWorkerAsync(); 
      Console.WriteLine("Im here NOW"); 

      Console.WriteLine(outLine.Data); //its outputed fine into the console 
     } 

    } 

    private void worker_DoWork_(object sender, DoWorkEventArgs e) 
    { 
     Console.WriteLine("I'm at worker_DoWork_"); 
     Delegate del = new DELEGATE(DoSomeWork); 
     this.Invoke(del); 
    } 

    private void DoSomeWork() 
    { 
     Thread.Sleep(1000); 
     textBox1.Text = "????"; // how to pass outline.Data in here 

    } 

} 

}

+0

pourquoi avez-vous commenté //worker.RunWorkerAsync(); ??? – NicoRiff

+0

car j'obtiens une erreur d'exception indiquant que Backgroundworker est déjà en cours d'exécution et ne peut pas s'exécuter en même temps. Par conséquent, je crois que DataReceivedHandler donne un coup de pied à l'un d'entre eux, mais je peux me tromper. –

+0

Vous devez décommenter cette ligne. Si vous essayez de l'exécuter une seconde fois, c'est à ce moment-là qu'il va planter. Donc d'abord, vérifiez si (! Worker.IsBusy) {worker.RunWorkerAsync(); } - Cela ne lui permettra que de s'exécuter s'il n'est pas en cours d'exécution. –

Répondre

0

Le problème est que vous décrivez RunWorkerAsync();. Cette méthode déclenche l'événement DoWork qui gère votre code asynchrone. Via EventArgs de DoWork, vous pouvez réutiliser vos résultats dans votre thread principal et les imprimer dans votre zone de texte. Vous pouvez obtenir le résultat dans RunWorkerCompleted-Event. Voici un petit exemple en fonction de votre code:

public partial class Form1 : Form 
    { 
    BackgroundWorker worker; 

    public Form1() 
    { 
     InitializeComponent(); 
     worker = new BackgroundWorker(); 
     worker.DoWork += worker_DoWork; 
     worker.RunWorkerCompleted += worker_Completed; 
    } 

    private void OutputHandler(object sendingProcess, DataReceivedEventArgs outLine) 
    { 
     if (outLine.Data != null) 
     { 
      if (!worker.IsBusy) //Check if Worker is working and avoid exception 
       worker.RunWorkerAsync();  
     } 
    } 

    private void worker_DoWork(object sender, DoWorkEventArgs e) 
    { 
     //Process some Long-Running Task 
     Thread.Sleep(5000) 
     e.Result = "Done!"; 
    } 

    private void worker_Completed(object sender, RunWorkerCompletedEventArgs e) 
    { 
     textbox.Text = e.Result.ToString(); 
    } 
    } 
} 

De plus, vous êtes peut-être intéressé à Task Library qui rendent la manipulation des fils plus faciles.

MISE À JOUR:

Vous dites:

Je veux mettre à jour mon temps réel en zone de texte.

Cela affichera le texte que votre fichier batch envoie à Standardoutput directement dans votre zone de texte. Donc je ne pense pas que tu aies besoin de plus.

private void OutputHandler(object sendingProcess, DataReceivedEventArgs e) 
    { 
     if (!string.IsNullOrWhiteSpace(e.Data)) 
      BeginInvoke(new MethodInvoker(() => { textBox1.Text = e.Data; })); 
    } 
+0

Merci, mais mon textBox n'est pas mis à jour en temps réel, c'est-à-dire chaque fois qu'une ligne est insérée dans la fenêtre cmd. Il sort seulement "Fait!". Une idée pourquoi? –

+0

@TomPisz Votre objectif n'est pas clair pour moi.Si vous appelez worker.RunWorkerAsync(); Cela exécutera exactement votre événement DoWork une fois. Donc, à coup sûr, il en résulte un fait! dans mon exemple. Notez que Backgroundworker ne veut pas dire sth, realtime. Il vous donne simplement la capacité d'une interface utilisateur réactive sur les opérations de longue durée. – Sebi

+0

Désolé Sebi mais c'est ce que j'ai trouvé sur différents sites et forums. J'ai besoin de mettre à jour la zone de texte en temps réel et quelqu'un a suggéré d'utiliser le document d'information. Je suis nouveau à C# et ce genre d'événements donc pas trop sûr de savoir comment le faire et essayez simplement l'approche d'erreur. Pouvez-vous me pointer dans la bonne direction? –

0

Grâce à @Sebi, j'ai réussi à trier tous les problèmes. Il s'avère que je n'ai pas besoin d'un BackgroundWorker comme certaines personnes l'ont suggéré.

Voir le code final qui fonctionne comme un charme:

using System; 
using System.Collections.Generic; 
using System.ComponentModel; 
using System.Data; 
using System.Drawing; 
using System.Linq; 
using System.Text; 
using System.Threading.Tasks; 
using System.Windows.Forms; 
using System.Diagnostics; 
using System.Threading; 


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

    private void button2_Click(object sender, EventArgs e) 
    { 

     Process process; 
     process = new Process(); 
     process.StartInfo.FileName = @"C:\\Project\Test\Other Data.bat"; 
     process.StartInfo.UseShellExecute = false; 
      process.StartInfo.CreateNoWindow = true; 
     process.StartInfo.RedirectStandardOutput = true; 
     process.OutputDataReceived += new DataReceivedEventHandler(OutputHandler); 

     process.StartInfo.RedirectStandardInput = true; 
     process.Start(); 
     process.BeginOutputReadLine(); 
     process.Close(); 
    } 

    private void OutputHandler(object sendingProcess, DataReceivedEventArgs outLine) 
    { 
     if (outLine.Data != null) 
     { 
      BeginInvoke(new MethodInvoker(() => { textBox1.AppendText(outLine.Data + Environment.NewLine); })); 
     } 

    } 
    } 

}

+0

Je suis heureux d'apprendre que vous avez résolu vos problèmes. – Sebi