2009-10-14 1 views
0

Так что яРабота текстового поля в форме из другого класса в C#

public class Form1 : Form {} 

и

class Updater {} 

И я textBox1 на Form1, наряду со многими другими элементами управления ...

Итак, вот моя дилемма: у меня есть цикл while(true) {} в Updater, и я не мог вставить его в класс Form1, потому что это мешало загрузке формы. И мне нужно обновить текстовое поле с несколькими строками (textBox1) в Form1, из Updater. Updater - это TCP-клиент, и когда он получает информацию, мне нужно, чтобы он был в +=, его информацию в текстовое поле. Но как я могу получить доступ к текстовому полю из потока, отличного от того, в котором он был создан?

Редактировать: Я ищу примеры кода, пожалуйста.

+0

делает Form1 есть ссылки на обновления? – CSharpAtl

ответ

2

Почему вы не объявляете событие в классе Updater? Затем вы можете поднять это событие, когда получаете данные из 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; 
    } 
} 

В Вас форме:

//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

Я добавил новый код. Он работает, я его протестировал. – TheVillageIdiot

1

Если Form1 имеет ссылку на Updater, то вы можете поместить событие в класс обновлений, к которому может подписаться Form1. Когда у Updater есть данные (или по какой-либо причине он нуждается в обновлении формы), он устанавливает событие, форма улавливает событие и обновляет текстовое поле.

Пример:

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

Одна вещь, на которую следует обратить внимание: Updater поднимет мероприятие самостоятельно (фоновый) поток. Итак, что-то - либо сборщик событий, либо обработчик событий - нужно будет перевести его в поток текстового поля, используя технику, описанную Nate. – itowlson

1

Cross-потоковая вызывается, когда поток используется для доступа к управлению, которые не создавали контроля. Чтобы обойти это, вы вызываете.

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

Пример:

/// <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; 
    }