3

Edit: Got quelque part, je l'espèreEn utilisant BackgroundWorker dans un objet et la mise à jour l'interface utilisateur

Voici ce que j'ai, mais je ne suis pas sûr de savoir comment je délègue mon bcLoad.ReportProgress (i) à la objet créé (c'est-à-dire comment faire le délégué afin qu'il puisse être passé). J'ai créé les événements d'objet qui fonctionnent en quelque sorte (je peux appeler ma méthode d'objet et je peux voir une modification déclenchée en lisant en lignes). Je sais quand objectChanged fonctionne (écrit en console). Cependant, bcLoad_RunWorkerCompleted ne semble pas fonctionner, le code de l'instruction if n'est jamais exécuté, donc je me trompe quelque part. Le fichier se charge cependant.

Quelqu'un pourrait-il s'il vous plaît possible définir comment créer le délégué, puis quelle section utiliser le délégué de passe dans (je suppose dans l'objet) et pourquoi bcLoad_RunWorkerComplete est nul. C'est vraiment la première fois que je l'ai utilisé, les événements et les délégués backgroundworkers en C#

/* 
The object which does file operations 
*/ 
using System; 
using System.Collections.Generic; 
using System.Text; 
using System.IO; 
using System.Collections; 
using System.Windows.Forms; 
using System.ComponentModel; 
using System.Data; 

namespace aodProductionViewer 
{ 
    public class fileOperationsSpecial 
    { 
     public event EventHandler Changed; 

     protected virtual void OnChanged(EventArgs e) 
     { 
      if (Changed != null) 
      { 
       Changed(this, e); 
      } 
     } 

     public fileOperationsSpecial() 
     {  } 

     /// <summary> 
     /// Count the number of lines in the file specified. 
     /// </summary> 
     /// <param name="f">The filename to count lines in.</param> 
     /// <returns>The number of lines in the file.</returns> 
     static long CountLinesInFile(string f) 
     { 
      long count = 0; 
      try 
      { 
       using (StreamReader r = new StreamReader(f)) 
       { 
        string line; 
        while ((line = r.ReadLine()) != null) 
        { 
         count++; 
        } 
       } 
      } 
      catch (Exception err) 
      { 
       string strTemp = "Error get number of lines for save game file. \n" + 
           err.ToString(); 
       errorDialog errDiag = new errorDialog("save game line count", 
             strTemp, true); 
      } 
      return count; 
     } 

     /// <summary> 
     /// Use this to readin in a file 
     /// </summary> 
     /// <param name="strPath">Path of file to read in</param> 
     /// <returns>a string array of the file</returns> 
     public string[] readFile(string strPath) 
     { 
      long lng_LineCount = CountLinesInFile(strPath); 
      string[] strReadIn = new string[lng_LineCount]; 
      try 
      { 
       long lngCount = 0; 
       using (StreamReader reader = new StreamReader(strPath)) 
       { 
        String line; 
        while ((line = reader.ReadLine()) != null) 
        { 
         strReadIn[lngCount] = line; 
         lngCount++; 
         OnChanged(EventArgs.Empty); 
        } 
       } 

      } 
      catch (Exception err) 
      { //    
      } 

      return strReadIn; 
     } 
    } 
} 

/* 
Event Listner 
*/ 
using System; 
using System.Collections.Generic; 
using System.Text; 

namespace aodProductionViewer 
{ 
    class EventListener 
    { 
     private fileOperationsSpecial FPS; 

     public EventListener(fileOperationsSpecial _fps) 
     { 
      FPS = _fps; 
      FPS.Changed += new EventHandler(objectChanged); 
     } 

     private void objectChanged(object sender, EventArgs e) 
     {   //changed has occured 
     } 

     public void Detach() 
     { 
      FPS.Changed -= new EventHandler(objectChanged); 
      FPS = null; 
     } 
    } 
} 

/* 
The backgroundWorker code (Part of) 
*/ 

    BackgroundWorker bcLoad = new BackgroundWorker(); 

    private void btt_load_save_game_Click(object sender, EventArgs e) 
    { 
     //Do some file dialog stuff 
     string strPath = null; 
     bcLoad.RunWorkerAsync(strPath); 
    } 

    void bcLoad_ProgressChanged(object sender, ProgressChangedEventArgs e) 
    { 
     tb_ProgressBar.Value = e.ProgressPercentage; 
    } 

    void bcLoad_DoWork(object sender, DoWorkEventArgs e) 
    { 
     string strPath = e.Argument as string; 
     fileOperationsSpecial FPS = new fileOperationsSpecial(); 
     EventListener listener = new EventListener(FPS); 
     string strArray = FPS.readFile(strPath); 
     listener.Detach(); 
    } 

    void bcLoad_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) 
    { 
     if (e.Result != null) 
     { 
      //Everything done 
      tb_ProgressBar.Visible = false; 
     } 
    } 

J'ai l'essentiel d'utiliser un BackgroundWorker pour faire un travail et mettre à jour l'interface utilisateur pour le progrès et l'achèvement , J'ai quelque chose de simple en ce moment Comme vous pouvez le voir, je passe une chaîne (qui est un chemin) Je lirais alors un fichier et je mettrais à jour une progression, actuellement je dors juste le fil et je règle la progression pour l'amour d'une démo. J'ai aussi l'intention de retourner un objet (tableau de chaînes) mais je n'ai pas encore trouvé de solution. Maintenant, ma question est, comment puis-je faire tout cela dans un objet créé par mon formulaire et toujours mettre à jour mon interface utilisateur? J'ai un objet qui fait actuellement des opérations sur des fichiers (lire un fichier, écrire, obtenir des informations).

Actuellement que ma compréhension signifie le formulaire ci-dessous démo va > BackgroundWorker> Formulaire de mise à jour pour le progrès.

Je voudrais qu'il aille

formulaire> Créer un objet> BackgroundWorker> Mise à jour sous forme de progrès> tableau de chaînes de retour

Je l'ai regardé au sujet et non fait ni queue ni tête de l'un des exemples, alors j'ai pensé que je demanderais à des gens qui sauraient. Est-ce seulement possible? Ce que j'essaie de faire, c'est de retirer tout traitement de fichier de mon formulaire pour qu'il soit plus facile à gérer et à maintenir.

Exemple de code complet sur la façon de faire ce serait fantastique!

Voici ce que je comprends à ce jour (rappelez-vous juste pour un bien d'exemples, ce ne sera pas compilé)

BackgroundWorker bcLoad = new BackgroundWorker(); 

    public frm_ProductionViewer() 
    { 
     InitializeComponent(); 
     load_settings(); 
     bcLoad.DoWork += new DoWorkEventHandler(bcLoad_DoWork); 
     bcLoad.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bcLoad_RunWorkerCompleted); 

     bcLoad.WorkerReportsProgress = true; 
     bcLoad.ProgressChanged += new ProgressChangedEventHandler(bcLoad_ProgressChanged); 

     bcLoad.WorkerSupportsCancellation = true; 
    } 

private void btt_load_save_game_Click(object sender, EventArgs e) 
    { 

     ts_label_GameLoaded.Text = "Loading"; 
     bcLoad.RunWorkerAsync(strPath); 
    } 

void bcLoad_ProgressChanged(object sender, ProgressChangedEventArgs e) 
    { 
     tb_ProgressBar.Value = e.ProgressPercentage; 
    } 

    void bcLoad_DoWork(object sender, DoWorkEventArgs e) 
    { 
      string strPath = e.Argument as string; 
      //load file 
      //Update progress 
      bcLoad.ReportProgress(80); 
      Thread.Sleep(300 * 5); 
      bcLoad.ReportProgress(100); 
    } 

    void bcLoad_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) 
    { 
     if (e.Result != null) 
     { 
      textBox1.Text = "done"; 
     } 
     tb_ProgressBar.Visible = false; ; 
     ts_label_GameLoaded.Text = "Loaded"; 
    } 

Répondre

3

Votre objet (qui fonctionne avec des fichiers) doit de préférence pas dépendre de l'interface utilisateur graphique ou Bgw.

Alors gardez votre Bgw avec (sur) votre formulaire et appelez dans le formulaire d'objet DoWork.

Pour signaler des commentaires, votre objet a besoin d'un événement (ou des méthodes principales prenant un paramètre délégué).

Dans le gestionnaire de cet événement (appelé sur le thread de travail), appelez le bcLoad.ReportProgress (pourcentage).


Réaction à l'édition:

  • vous avez besoin d'un EventArgs de type avec une salle pour le pourcentage, comme EventHandler<ProgressEventArgs>, vous avez probablement écrire ProgressEventArgs. Je ne pense pas que vous souhaitiez une classe EventListener distincte. C'est le travail Forms. Que vous obtient:

 

class Form ... 
{ 
    private void objectChanged(object sender, ProgressEventArgs e) 
    { //changed has occured 
     // trigger the Bgw event 
     // or use Form.Invoke here to set the progress directly 
     bcLoad.ReportProgress(e.Percentage);   
    } 

} 

Ainsi, un 'changement' filtres maintenant par 2 eventhandlers. 1 pour séparer la dépendance du FPS, 1 pour synchroniser avec le Formulaire.

+0

Merci Je vais quelque part, je me dirige dans votre direction, mais je suis aux prises avec la partie délégué, puis en utilisant le délégué dans l'objet. J'ai modifié le post principal avec mes modifications et problèmes. Merci pour votre aide: D – Shibby

0

Si vous voulez une classe (autre que la forme) pour encapsuler le travailleur de fond, une approche consiste à ajouter un événement à cette classe et abonnez-vous à cet événement dans le formulaire:

  • classe X encapsule fond travailleur et publie un « Done » événement
  • forme crée instance de classe X, et gestionnaire d'événements pour la méthode « Terminé » événement
  • appelle forme l'instance de classe X « Do travail async » et se déplace sur
  • notifie son instance de classe X forme lorsque le travail asynchrone se termine via Done e Évent, passant la chaîne ou tout état dont le formulaire a besoin
Questions connexes