C# 为什么';定时器不能在程序中启动吗?

C# 为什么';定时器不能在程序中启动吗?,c#,winforms,C#,Winforms,我有一个简单的C#程序(在MS visual Studio 2010中完成)。 它是一个windows窗体,上面有一个按钮。正如你所看到的,这只是一个简单的程序,但我仍然坚持下去。 我试图理解C#计时器和C#中的全局变量 当按下按钮时,我希望它执行以下操作 此时(每秒)会出现一个消息框,显示号码 按钮按下后的秒数。 它通过将变量starttimer设置为true(在一个函数中)来工作,在另一个函数中,当检测到starttimer等于true时,它会在消息框中以秒为单位显示时间 但是,它似乎没有检

我有一个简单的C#程序(在MS visual Studio 2010中完成)。 它是一个windows窗体,上面有一个按钮。正如你所看到的,这只是一个简单的程序,但我仍然坚持下去。 我试图理解C#计时器和C#中的全局变量

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

但是,它似乎没有检测到另一个函数中的
starttimer
等于true。starttimer变量的作用是检测用于每秒开始显示消息框的按钮按下情况

那么,修复此程序的最简单方法是什么

PS当程序运行时,如果没有
starttimer
的代码,它会每秒显示一次消息框(当程序启动时)

显示了程序windows窗体的图片-正如您所看到的,它非常简单,只需一个按钮

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;
        }
    }
}

需要启用计时器

myTimer.Enabled = true
那么,修复此程序的最简单方法是什么


实际上,点击按钮,使变量
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子句检查
if(starttimer==true)
,因为您从未从代码中的其他地方调用此方法


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

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

myTimer.Enabled = true
解决方案非常简单,将
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();
        }
    }
}
if(something)
{
    int x = 5;
}
x = x + 5; //x doesn't exist here! It disappears at }
哦,关于整个“范围”的事情。在C#中,作用域基本上是介于a{和a}之间的东西。在方法和普通代码中,作用域内创建的变量不能被作用域外的代码看到。这就是为什么在执行以下操作时会出现编译器错误:

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();
        }
    }
}
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

类作用域中的任何内容都可以被类中的所有方法看到,这就是为什么计时器现在仍然存在的原因。不过类的作用域略有不同,因为如果其他类前面有public,您可以在它们中看到它们。方法也是如此(请注意,您的所有方法都有“private”,因此外部类不能调用它们。将它们更改为public,它们就可以了!)

您从不调用DoeverySecond,它是C#,而不是“C Sharp”,并且您不想每次都创建一个新计时器,“mytimer”应该移到类中。格式化您的代码,提问。。。基本上一切都好。此问题在当前状态下不可读。是否设置了断点?你点击按钮点击代码了吗?您是否在customfn中点击了断点?否。
Start()
将启用计时器。该操作名为
mytimer.Start()在启用计时器的构造函数中。实际上是点击按钮,这样变量starttimer就被设置为true,您就可以在每秒钟看到MessageBox。你的程序行得通-我仍然没有让它工作-我一定错过了一些简单的东西你的右startimer可以有一个更好的名字-它的目的是在屏幕上显示计时器-一个标志来检测按钮按下你使用的是什么版本的C Sharp?2010年?我使用的是VS 2013和2015。我无法想象他们会在两个版本之间改变计时器的工作方式。您可以将变量设置为代码中的其他位置(未发布的部分),或者只需按下按钮即可。我无法想象一旦事件被注册,if子句实际上就不起作用了。计时器将保留在内存中,直到敌人注销或程序结束。只要事件已注册,垃圾收集器就不会触动计时器。我在原始程序中没有使用Form1_load。Form1_load—从您的代码—只要程序在屏幕上运行,它就会自动被调用,对吗?当表单加载到屏幕/图形内存中时,Form1\u load在开始时不会被调用一次