C#,如何在其他线程中创建的当前线程中获取某些内容?

时间:2012-06-29 06:45:39

标签: c# multithreading

我正在用c#编写聊天客户端/服务器应用程序,我遇到了线程问题。我写了这个简单的代码来展示我的问题。

我使用thread_1显示Form但它只显示了一秒(也许thread_1终止并关闭了Form,但我IsAlive说它还活着!)。 Thread_2尝试访问在主线程上创建的texBox,但它显示了我:

  

“跨线程操作无效:从a访问控制'textBox2'   线程以外的线程。“

我不知道如何解决第一个问题,但我解决了BackgroundWorker的第二个问题,但我喜欢用线程来做。有什么办法吗?

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

    Thread t1;
    Thread t2;


    private void button1_Click(object sender, EventArgs e)
    {

        t1 = new Thread(doThread1);
        t1.Name = "thread_1";

        t2 = new Thread(doThread2);
        t2.Name = "thread_2";

        t1.Start();
        t2.Start();

        MessageBox.Show(t1.IsAlive.ToString());
    }

    private void doThread1()
    {
        Form frm2 = new Form();
        frm2.Show();
    }


    private void doThread2()
    {
        try
        {
            for (int j = 10000; j > 0; j--)
                textBox.Text = j.ToString();
        }
        catch (Exception ex)
        {
            MessageBox.Show(ex.Message);
        }
    }


}

2 个答案:

答案 0 :(得分:2)

正如Linkerro所提到的,你想要取出你调用线程1的线程,因为当你启动时你的UI已经在一个线程中(所有程序都有一个主线程开始)。虽然您处于正确的轨道上,但您希望将任何长时间运行的任务放在单独的线程上,这样它就不会阻止UI。唯一的技巧是你不能直接从后台线程设计UI对象,它们必须从拥有它们的线程中操作(这是你得到的错误信息)。

幸运的是,在.NET中有一种非常简单的方法可以实现这一点。在WPF中,您使用UiComponent.Dispatcher.Invoke()和Winforms只使用UiComponent.Invoke()。这允许您的后台线程转到UI组件所在的线程来更新它。

Invoke接受一个委托,该委托代表您希望在UI线程上运行的操作。在我的例子中,我传入一个动作,该动作使用lambada表达式初始化,不带任何参数并且不返回任何值。

试试这个

private void doThread2()
{
    try
    {
        for (int j = 10000; j > 0; j--)
        {
            textBox.Invoke(new Action(() =>
                textBox.Text = j.ToString()));
        }
    }
    catch (Exception ex)
    {
        MessageBox.Show(ex.Message);
    }
}

以下是如何使用“任务”执行此操作的完整示例。你会看到它在计数时你可以自由地移动窗口并且它不会锁定。但是取出Task并离开循环,你会看到窗口是如何冻结的,因为循环会阻塞UI线程。

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

    private void button1_Click(object sender, EventArgs e)
    {
        Task.Factory.StartNew(() =>
        {
            for (int x = 0; x < 100000000; x++)
            {
                label1.Invoke(new Action(() =>
                    label1.Text = x.ToString()));
            }
        });
    }
}

答案 1 :(得分:0)

请参阅Writing to a TextBox from another thread?,我对此回答了您访问在另一个线程中创建的对象的问题。

第一次链接出了问题。