0

我使用 C# 和 .NET 4.0 创建了一个新的 Windows 窗体应用程序,并且我有一个必须每 60 秒自动调用一次的函数。我的问题是我不知道在哪里调用这个函数。.NET 表单似乎没有内置的更新事件。

我将如何让这个函数每 60 秒调用一次?对不起,如果这是一个初学者的问题。

4

3 回答 3

2

您可以设置一个计时器以每 16 毫秒(即 1/60 秒)调用一次回调。

@spender 提到的重要一点:如果您需要非常精确的计时,例如精确每 1/60 秒的精度,您将不会对此解决方案感到满意。Windows 本身并不能很好地在这种情况下进行高分辨率计时。向@spender 提出建议以供提及。

这是一个示例类,粗略地描述了它在普通香草类中的外观,因此您需要将其调整为您的表单:

您可能还想在后台线程上调用它,但如果您是 WinForms 的新手,我们将从小块开始。让我们先试试计时器,然后从那里开始。

class Demo{

   System.Timers.Timer myTimer;

   void InitializeTimer(){
      myTimer = new Timer(16); // elaps every 1/60 sec , appx 16 ms.
      myTimer.ElapsedEventHandler+=new ElapsedEventHandler(myTimerEventHandler); //define a handler
      myTimer.Enabled=true; //enable the timer.
   }

   void myTimerEventHandler(object sender, ElapsedEventArgs e){
     // do your thing here
   }
}

编辑:后台线程创建和基于调用的 GUI 更新的额外演示代码

正如我在下面的评论中所指出的,这并没有我想要的那么完美,但我认为它说明了要点。它定义了一个 BackgroundWorker 线程来将线程调用移动到后台;线程回调检查是否需要调用 Invoke,并通过委托调用直接回调自身,以允许在“if (InvokeRequired)”语句的“else”块中更新自定义表单。简而言之,一个后台线程启动,并启动一个定时器;当计时器到时,它调用后台线程上的更新程序,它检查是否必须调用 Invoke,如果是,则通过调用方法执行线程上下文切换回 GUI 线程,然后执行图形用户界面更新。将您的自定义更新代码放在那个“其他”块中。我希望这有帮助!!!

public partial class Form1 : Form
{
    delegate void FormUpdateDelegate(object sender, ElapsedEventArgs e);
    public BackgroundWorker backgroundThread; 
    System.Timers.Timer foo;
    Random colorgen = new Random();
    public Form1()
    {
        InitializeComponent();

        backgroundThread = new BackgroundWorker();
        backgroundThread.DoWork+=new DoWorkEventHandler(backgroundThread_DoWork);
        backgroundThread.RunWorkerAsync();
    }

    public void formUpdater(object sender, ElapsedEventArgs e)
    {
        if (InvokeRequired)
        {
            FormUpdateDelegate d = new FormUpdateDelegate(formUpdater);
            Invoke(d, new object[] { sender, e });
        }
        else
        {
            // Do your form update here
            this.label1.ForeColor = Color.FromArgb(colorgen.Next());
        }
    }

    public void backgroundThread_DoWork(object sender, DoWorkEventArgs e)
    {
        foo = new System.Timers.Timer(16);
        foo.Elapsed += new ElapsedEventHandler(formUpdater);
        foo.Start();
    }

}
于 2012-09-29T22:03:41.000 回答
0

我只是在控制台应用程序中设置它,它每秒运行良好:

        var timer = new System.Timers.Timer(1000);

        timer.Enabled = true;
        timer.Elapsed += new ElapsedEventHandler(delegate(object sender, ElapsedEventArgs eventArgs)
                                                         {
                                                             Console.WriteLine("Elapsed");
                                                         });
于 2012-09-29T22:09:54.837 回答
0

当您至少需要20每秒精确次时,寄希望于系统计时器是一种不好的做法。

我建议使用像这样的循环

Timespan timePerFrame = Timespan.FromMilliseconds(16);

while (_isRunning)
{
    Stopwatch timer = Stopwatch.StartNew()

    // Action.

    while (timer.ElapsedMilliseconds < timePerFrame) { /* Nothing? */ }
}

如果您的系统支持高精度秒表,这将为您提供完整的精度。(.IsHighResolution场)。

于 2012-09-29T22:10:37.947 回答