开发者

Working a textbox in a form from another class in C#

So I have

public class Form1 : Form {}

and

class Updater {}

And I have textBox1 on Form1, along with many other controls...

So here is my dilemma: I have a while(true) {} loop in Updater, and I couldn't stick it in the Form1 class, because it was preventing the form from loading. And I need to update a multi-lined textbox (textBox1) on Form1, from Updater. Updater is a TCP client, and when it receives information I need it to += its information into the textbox.. But how do I access the textbox from a thread diffe开发者_运维问答rent from the one it was created in?

Edit: I'm looking for code examples, please.


Why don't you declare an event in Updater class? Then you can raise this event when you get data from 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;
    }
}

In you form:

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


If Form1 has a reference to Updater then you can put an event on the Updater Class that Form1 can subscribe to. When Updater has data (or whatever reason it needs to update the form) it sets the event, the form catches the event and updates the textbox.

Example:

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");
                }
            }
        }

    }


Cross-threading is caused when a thread is used to access a control that did not create the control. To get around it you Invoke.

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

Example:

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

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜