2009-10-14 5 views
0

donc jeTravailler une zone de texte sous une forme d'une autre classe en C#

public class Form1 : Form {} 

et

class Updater {} 

Et je textBox1 sur Form1, ainsi que de nombreux autres contrôles ...

Voici donc mon dilemme: j'ai une boucle while(true) {} dans Updater, et je ne pouvais pas la coller dans la classe Form1, car elle empêchait le chargement du formulaire. Et j'ai besoin de mettre à jour une zone de texte multilignée (textBox1) sur Form1, à partir de Updater. Updater est un client TCP, et quand il reçoit des informations j'ai besoin de += ses informations dans la zone de texte. Mais comment accéder à la zone de texte à partir d'un thread différent de celui dans lequel il a été créé?

Edit: Je cherche des exemples de code, s'il vous plaît.

+0

ne Form1 une référence à Updater? – CSharpAtl

Répondre

2

Pourquoi ne pas déclarer un événement dans la classe de mise à jour? Vous pouvez ensuite déclencher cet événement lorsque vous obtenez des données de TCP.

public class Updater 
{ 
    public delegate void DataReceivedEventHandler(object sender,DataEventArgs e); 
    public event DataReceivedEventHandler DataReceived = delegate { }; 

    public void ReadData() 
    { 
     //here you will get data from what ever you like 
     //upon recipt of data you will raise the event. 

     //THIS LOOP IS FOR TESTING ONLY 
     for (var i = 1; i < 101; i++) 
     { 
      //PASS REAL DATA TO new DataEventArgs 
      DataReceived(this, new DataEventArgs("Event " + i)); 
      Thread.Sleep(500); 
     } 
    } 
} 

public class DataEventArgs : EventArgs 
{ 
    public string Data { get; set; } 
    public DataEventArgs(string data) : base() 
    { 
     Data = data; 
    } 
} 

En vous former:

//you will setup "Updater" in some else way. I've written this function 
    //which I call on a button click for testing 
    private void Init() 
    { 
     var u = new Updater(); 
     u.DataReceived += delegate(object sender, DataEventArgs e) 
           { SetTextboxText(e.Data); }; 

     BackgroundWorker bw = new BackgroundWorker(); 

     bw.DoWork += delegate(object sender, DoWorkEventArgs e) 
       { ((Updater)e.Argument).ReadData(); }; 
     bw.RunWorkerAsync(u); 
    } 

    private void SetTextboxText(string s) 
    { 
     if (TEXT_BOX.InvokeRequired) 
     { 
      //This techniques is from answer by @sinperX1 
      BeginInvoke((MethodInvoker)(() => { SetTextboxText(s); })); 
      return; 
     } 
     TEXT_BOX.Text += Environment.NewLine + s; 
    } 
+0

J'ai ajouté un nouveau code. Ça marche, je l'ai testé. – TheVillageIdiot

1

Si Form1 contient une référence à Updater, vous pouvez placer un événement sur la classe Updater à laquelle Form1 peut s'abonner. Lorsque Updater dispose de données (ou de toute autre raison nécessaire pour mettre à jour le formulaire), il définit l'événement, le formulaire attrape l'événement et met à jour la zone de texte.

Exemple:

public partial class Form1 : Form 
    { 
     public Form1() 
     { 
      InitializeComponent(); 
      Updater textboxUpdater = new Updater(); 
      textboxUpdater.Updated += s => {textBox1.Text = s;}; 
     } 
    } 


public class Updater 
    { 
     public delegate void UpdateEventHandler(string eventName); 
     public event UpdateEventHandler Updated = delegate { }; 

     private bool needUpdating; 
     public void Process() 
     { 
      while (true) 
      { 
       //Processing 
       if (needUpdating) 
       { 
        Updated("something"); 
       } 
      } 
     } 

    } 
+0

Une chose à surveiller: Updater déclenchera l'événement sur son propre thread (arrière-plan). Donc, quelque chose - soit le relanceur d'événement ou le gestionnaire d'événement - devra le faire passer dans le fil de la boîte de texte en utilisant la technique décrite par Nate. – itowlson

1

Cross-threading est causée lorsqu'un fil est utilisé pour accéder à un contrôle qui n'a pas créé le contrôle. Pour contourner cela, vous invoquez.

http://msdn.microsoft.com/en-us/library/zyzhdc6b.aspx

Exemple:

/// <summary> 
    /// This is a thread safe operation. 
    /// </summary> 
    /// <param name="text"></param> 
    public void SetTextBoxText(string text) 
    { 
     if (InvokeRequired) 
     { 
      Invoke((MethodInvoker)delegate { SetText(text); }); 
      return; 
     } 

     // To get to this line the proper thread was used (by invoking) 
     myTextBoxt.Text += text; 
    } 

    /// <summary> 
    /// This is an alternative way. It uses a Lambda and BeginInvoke 
    /// which does not block the thread. 
    /// </summary> 
    /// <param name="text"></param> 
    public void SetTextBoxText(string text) 
    { 
     if (InvokeRequired) 
     { 
      BeginInvoke((MethodInvoker)(() => { SetText(text); })); 
      return; 
     } 

     // To get to this line the proper thread was used (by invoking) 
     myTextBox.Text += text; 
    } 
Questions connexes