如何在线程之间传递值?

时间:2010-09-29 10:34:12

标签: c# multithreading

我有一个带有MainForm表单的Windows窗体程序。按下按钮,我启动一个代码,在另一个线程上每0.5秒运行一次(脉冲)。我想从Pulse方法修改很多东西,比如我的MainForm上的标签,进度条。这怎么可能? 所以我想知道,如何在该线程中与变量,值和MainForm进行交互。相互修改等。

点击foo按钮,我告诉我的脉动器启动。 Pulsator.Initialize();

这是Pulsator课程:

public static class Pulsator
{
    private static Thread _worker;

    public static void Initialize()
    {
        _worker = new Thread(Pulse);
        _worker.IsBackground = true;
        _worker.Start();
    }

    public static void Close()
    {
        if (_worker != null)
        {
            _worker.Abort();
            while (_worker.IsAlive || _worker.ThreadState != ThreadState.Stopped)
            {
               //closing
            }
        }
    }

    public static void Pulse()
    {
        if (_worker != null)
        {
            while (true)
            {
                SomeOtherClass.Pulse();
                Thread.Sleep(500);
            }
        }
        else
        {
            SomeOtherClass.Pulse(); // yeah I know this doesnt needed
        }
    }
}

SomeOtherClass Pulse方法如下:

    public static void Pulse()
    {
        //here I will have several values, variables, and I want to show results,
        // values on my MainForm, like:
        Random random = new Random();
        MainForm.label1.Text = random.Next(123,321).ToString(); // I hope you know what I mean
    }

当然这很复杂,这只是一个愚蠢的例子。

4 个答案:

答案 0 :(得分:4)

通常,在WinForms中,修改拥有控件的底层非托管资源(窗口句柄)的线程之外的可视控件的状态是不安全的。您必须使用Control.Invoke方法来安排在控件的拥有线程上执行修改。

答案 1 :(得分:1)

为什么不使用System.Timers.Timer?

E.g:

        trainPassageTimer = new Timer(500);
        trainPassageTimer.AutoReset = true;
        trainPassageTimer.Elapsed += TimeElapsed;

        ...

        private void TimeElapsed(object sender, ElapsedEventArgs elapsedEventArgs)
        {
// Do stuff
// Remember to use BeginInvoke or Invoke to access Windows.Forms controls
        }

答案 2 :(得分:1)

正如其他人已经提到的那样,您必须使用Control.Invoke从后台线程更改UI控件。

另一种选择是使用System.ComponentModel.BackgroundWorker(它在表单设计器工具箱中可用)。然后,您可以使用常规表单计时器,调用RunWorkerAsync-Method并在DoWork事件处理程序中执行后台工作,该处理程序将从另一个线程自动调用。

从那里,您可以通过调用ReportProgress将数据传回主线程。这将在主线程中引发ProgressChanged事件,您可以在其中自由更新所有UI控件。

答案 3 :(得分:0)

C#2或更高版本(VS2005)有匿名代表(而C#3有lambda,这是同一个想法的稍微整洁的版本)。

这允许使用可以“查看”周围范围中的变量的函数启动线程。所以没有必要明确地传递任何东西。在缺点方面,存在线程意外地依赖于它不应该的东西的危险(例如,在其他线程中正在改变的变量)。

_worker = new Thread(delegate 
{
    // can refer to variables in enclosing scope(s).
});