我有一个带有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
}
当然这很复杂,这只是一个愚蠢的例子。
答案 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).
});