C# 如何在线程之间传递值?
我有一个带有窗体MainForm的windows窗体程序。按下一个按钮,我启动一个代码,在另一个线程上每0.5秒运行一次(脉冲)。我想从Pulse方法中修改很多东西,比如主窗体上的标签、进度条。这怎么可能? 所以我想知道,如何在线程和主窗体中与变量、值交互。相互修改等 点击foo按钮,我告诉我的脉动器开始。 Pulsator.Initialize() 这是脉动器等级:C# 如何在线程之间传递值?,c#,multithreading,C#,Multithreading,我有一个带有窗体MainForm的windows窗体程序。按下一个按钮,我启动一个代码,在另一个线程上每0.5秒运行一次(脉冲)。我想从Pulse方法中修改很多东西,比如主窗体上的标签、进度条。这怎么可能? 所以我想知道,如何在线程和主窗体中与变量、值交互。相互修改等 点击foo按钮,我告诉我的脉动器开始。 Pulsator.Initialize() 这是脉动器等级: public static class Pulsator { private static Thread _worker
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
}
}
}
另一类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
}
当然,这非常复杂,这只是一个愚蠢的例子。通常,在WinForms中,在拥有控件底层非托管资源(窗口句柄)的线程之外修改可视控件的状态是不安全的。您必须使用该方法来计划在控件所属线程上执行修改。C#2或更高版本(VS2005)具有匿名委托(C#3具有lambdas,这是相同想法的一个稍微整洁的版本) 这些允许线程使用一个函数启动,该函数可以“查看”周围范围中的变量。所以没有必要显式地传递任何信息。另一方面,线程可能会意外地依赖于它不应该依赖的内容(例如,其他线程中正在更改的变量)
为什么不使用System.Timers.Timer 例如:
正如其他人已经提到的,您必须使用Control.Invoke从后台线程更改UI控件 另一个选项是使用System.ComponentModel.BackgroundWorker(可在表单设计器工具箱中找到)。然后,您可以使用一个常规的forms计时器来调用RunWorkerAsync方法,并在DoWork事件处理程序中执行后台工作,该处理程序将从另一个线程自动调用
从那里,您可以通过调用ReportProgress将数据传递回主线程。这将在主线程中引发ProgressChanged事件,您可以在主线程中自由更新所有UI控件。另外,请注意,调用thread.Abort会引发ThreadAbortException,您需要在Close方法System.Windows.Forms.Timer中处理该异常。Timer是执行UI工作的更好选择:
_worker = new Thread(delegate
{
// can refer to variables in enclosing scope(s).
});
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
}