为什么程序中的定时器启动没有?

时间:2017-07-26 15:03:55

标签: c# winforms

我有一个简单的C#程序(在MS visual Studio 2010中完成)。 它是一个窗口形式,上面有一个按钮。正如你可以看到它只是一个简单的程序,但我坚持它。 我试图在C#中理解C#定时器和全局变量。

按下按钮时,我希望它执行以下操作 出现一个消息框(每秒一次)显示该号码 按下按钮后的秒数。 它应该通过将变量starttimer设置为true(在一个函数中)以及在检测到starttimer等于true时在另一个函数中工作,它在消息框中显示以秒为单位的时间。

然而,它似乎没有检测到starttimer在另一个函数中等于true。 starttimer 变量的目的是检测按下按钮,以便每秒开始显示消息框。

那么修复这个程序最简单的方法是什么?

PS当程序在没有starttimer代码的情况下运行时,它会每秒显示一个消息框(程序启动时)。

显示程序窗口窗体的图片 - 您可以看到它非常简单 - 只需一个按钮。

namespace timerprogram
{
    public partial class doeverysecond : Form
    {
        int thetimeinsecs  = 0; 
        bool starttimer = false;


        private void Form1_Load(object sender, EventArgs e)
        {

        }    

        private void customfn(object source, ElapsedEventArgs e)
        {
            if (starttimer == true)
            {
                thetimeinsecs = thetimeinsecs + 1;
                MessageBox.Show(thetimeinsecs.ToString());
            }
        }

        public doeverysecond()
        {
            {            
                {   
                    System.Timers.Timer mytimer = new System.Timers.Timer();
                    mytimer.Elapsed += new ElapsedEventHandler(customfn);
                    mytimer.Interval = 1000;
                    mytimer.Start();
                }
            }
        }

        private void button1_Click(object sender, EventArgs e)
        {
            starttimer = true;
        }
    }
}

enter image description here

3 个答案:

答案 0 :(得分:2)

  

那么修复这个程序最简单的方法是什么?

实际上是按下按钮,因此变量starttimer设置为true,您将能够每秒看到MessageBox。你的节目有效!

除此之外,通过一个方法可以通过点击按钮启动计时器,将更多结构带入您的程序会很好:

    private void button1_Click(object sender, EventArgs e)
    {
        if(!mytimer.Enabled) // this will prevent a double start
        {
            starttimer = true;
            mytimer.Start();
        }
    }

构造函数应该摆脱计时器起始行:

public doeverysecond()
{
    {   
        System.Timers.Timer mytimer = new System.Timers.Timer();
        mytimer.Elapsed += new ElapsedEventHandler(customfn);
        mytimer.Interval = 1000;
    }
 }

责任分工在这里很重要。构造函数用于初始化变量。所以这是他的工作。按钮启动计时器。

检查if (starttimer == true)的if子句实际上不是必需的,因为您从不在代码中的其他位置调用此方法。

将布尔变量设置为true会使启动计时器。这只是一面旗帜!

答案 1 :(得分:0)

定时器可能有点奇怪,但看起来你的主要问题是mytimer在方法范围内,这意味着当该方法结束时,垃圾收集器会清除mytimer并且它停止运行。发生这种情况是因为当方法结束时,无法再从代码中的其他位置访问mytimer。为了节省内存,.NET会在你之后清理,但在这种特殊情况下,它并不够聪明,知道你实际上还在使用计时器。

解决方案非常简单,将mytimer放在班级。您也可以摆脱starttimer bool,因为现在您可以检查计时器本身以查看它是否正在运行。

您可以执行以下操作:

namespace timerprogram
{
    public partial class doeverysecond : Form
    {
        //Timer is class level, so it sticks around and can be called from
        //multiple methods
        System.Timers.Timer mytimer = new System.Timers.Timer();
        int thetimeinsecs = 0; 

        private void Form1_Load(object sender, EventArgs e)
        {
            //Setup the timer, but don't start it
            mytimer.Elapsed += new ElapsedEventHandler(customfn);
            mytimer.Interval = 1000;
        }    

        private void customfn(object source, ElapsedEventArgs e)
        {
            //We can check the timer itself to see if it's running!
            if (mytimer.Enabled)
            {
                thetimeinsecs = thetimeinsecs + 1;
                MessageBox.Show(thetimeinsecs.ToString());
            }
        }

        private void button1_Click(object sender, EventArgs e)
        {
            //Start the timer!
            mytimer.Start();
        }
    }
}

哦,关于整个'范围'事情。在C#中,范围基本上介于{和}之间。在方法和普通代码中,范围外的代码无法看到范围内创建的变量。这就是为什么如果你执行以下操作会出现编译器错误的原因:

if(something)
{
    int x = 5;
}
x = x + 5; //x doesn't exist here! It disappears at }

您可以从范围内的范围外访问事物,所以

int x = 0;
if(something)
{
    x = 5; //x exists in an outside scope
}
x = x + 5; //This is fine

类中的所有方法都可以看到类范围内的任何内容,这就是定时器现在可以使用的原因。类范围略有不同,因为如果它们在它们之前公开,你可以在其他类中看到它们。方法也是如此(请注意,您的所有方法都有'私有',因此外部课程无法调用它们。将它们更改为公共,他们可以!)

答案 2 :(得分:-3)

需要启用计时器。

myTimer.Enabled = true