C# Winform应用程序:线程和计时器出现问题

C# Winform应用程序:线程和计时器出现问题,c#,winforms,visual-studio,timer,threadpool,C#,Winforms,Visual Studio,Timer,Threadpool,我正在用Winform(C#)编写一个非常简单的程序 但是,我在线程和计时器方面遇到了一些问题。我收到一条消息,称为“线程”(0x1e30)已退出,代码为0(0x0)。“我了解到,当线程成功停止时,会发生这种情况。然而,这不是我想要的 这个程序叫做“你现在在做什么?”它的目的是坐在托盘中,以随机的时间间隔(比如15到120分钟)弹出一个文本提示,让我写下我现在正在做什么。然后将其记录到一个简单的txt文件中。这个想法是,仅仅是对我正在做的事情进行“坦白”的行为就能让我更加意识到我是如何在电脑前度

我正在用Winform(C#)编写一个非常简单的程序

但是,我在线程和计时器方面遇到了一些问题。我收到一条消息,称为“线程”(0x1e30)已退出,代码为0(0x0)。“我了解到,当线程成功停止时,会发生这种情况。然而,这不是我想要的

这个程序叫做“你现在在做什么?”它的目的是坐在托盘中,以随机的时间间隔(比如15到120分钟)弹出一个文本提示,让我写下我现在正在做什么。然后将其记录到一个简单的txt文件中。这个想法是,仅仅是对我正在做的事情进行“坦白”的行为就能让我更加意识到我是如何在电脑前度过时间的(并希望变得更有效率)

当我写了一些文字(例如“浏览StackOverflow”)后,它会再次最小化到托盘,并开始一个新的倒计时,以确定何时弹出

问题是主线程在一段时间后不知何故停止,从而使计时器也停止。我不知道为什么;在VisualStudio2012中创建WinForm项目时,除了默认设置之外,我没有对线程执行任何操作

记录输出时,如下所示(我附加了注释):

  • 5//应用程序开始倒计时
  • 四,
  • 三,
  • 二,
  • 一,
  • 0//计时器完成,显示窗口并等待点击“开始!”按钮
  • 4/新倒计时
  • 三,
  • 二,
  • 一,
  • 0//不显示窗口(如预期的那样)
  • 0
  • 线程“”(0x6e0)已退出,代码为0(0x0)
  • 0
  • 0//等等
我对计时器和线程的了解还不足以检测出线程“无名”为什么会在那个特定时刻停止

这是我的代码(我删除了一些不太重要的代码;您可以在这里看到它们:):

namespace您现在正在做什么
{
公共部分类Form1:Form
{
私有字符串_text;//用户将写入的文本
private double\u timeLeft;//倒计时时间
公共表格1()
{
初始化组件();
label2.Visible=true;//显示计时器的调试标签
this.WindowState=FormWindowState.Minimized;//在任务栏中启动最小化
_text=”“;//重置文本
WriteLog(true);//今天第一次写
GetRandomTime();//获取新的随机时间间隔
timer1.Interval=1000;//秒
timer1.Start();//启动计时器
}
//Go按钮(通过单击或按Enter键)
私有void HitGoButton()
{
_text=DateTime.Now+“-”+textBox1.text;//追加日期和时间
书面记录(假);
_text=“”;
GetRandomTime();
this.WindowState=FormWindowState.Minimized;
}
//打开txt文件并写入
私人作废记录(bool startOfTheDay)
{
//使用StreamWriter写入txt文件
}
私有void GetRandomTime()
{
Random rand=新随机((int)DateTime.Now.Ticks);
_timeLeft=rand.Next(1,2)*5;//乘以60得到分钟而不是秒
}
//倒计时到随机时间,然后显示该框
私有无效计时器1_刻度(对象发送方,事件参数e)
{
//倒计时
如果(_timeLeft>0)
_时间限制--;
label2.Text=\u timeLeft.ToString();//显示时间的调试标签
notifyIcon1.Text=\u timeLeft.ToString();//调试显示时间在任务栏中
Console.WriteLine(_timeLeft);//调试控制台窗口的写入时间
//如果时间用完-->显示窗口

如果(\u timeLeft你不应该在表单显示给用户时停止计时器吗?然后在它隐藏时重新启用倒计时。

如果我错了,请纠正我,但在我看来,你希望在15分钟到120分钟之间的随机时间弹出窗口吗?我将分为几步

第一步

如果是这种情况,那么您的
GetRandomTime
方法应该如下所示:

private void GetRandomTime()
    {
        Random rand = new Random(); /*You do not need to supply it the current
 datetime as the random class uses a time dependent default seed value */

//look at the constructor http://msdn.microsoft.com/en-us/library/system.random.aspx 

        _timeleft = rand.Next(15, 120) * 60 * 1000; /*here you are telling the random 
"I want any number between 15 and 120 but in order to get this to vibe with the timer's
 interval format you need to multiply by 60 first for the seconds and 1000 to convert
 to milliseconds. */

    }
基本上从上面的随机数来看,如果你最后得到24。,你乘以60得到1440,再乘以1000得到1440000,这是24分钟内的毫秒数。你之前得到的总是5。现在进入第二步

第二步

现在你需要改变你的记号处理程序

private void timer1_Tick(object sender, EventArgs e)
    {
        // count down
        if (_timeLeft > 0)
            _timeLeft = _timeleft - 1000; //Since your interval is 1s subtract that.

        label2.Text = ((_timeLeft / 1000) / 60).ToString() + " minutes left"; // convert back to minutes
        notifyIcon1.Text = ((_timeLeft / 1000) / 60).ToString() + " minutes left"; 
        Console.WriteLine(((_timeLeft / 1000) / 60).ToString() + " minutes left"); 

        // if time ran out --> show the window
        if (_timeLeft <= 0)
        {
            this.WindowState = FormWindowState.Normal;
        }
    }

我发现了问题所在。显然,我正在重写表单调整大小事件中的某些功能,这使程序无法工作

如果我将以下内容注释掉,则该程序将按预期工作:

private void Form1_Resize_1(object sender, EventArgs e)
        {
            /*if (WindowState == FormWindowState.Minimized)
            {
                this.Hide(); // only show in tray icon, not in task bar
            }
            else if (WindowState == FormWindowState.Normal)
            {
                this.Show();
            }*/
        }

你也可以显示设计器文件吗?(在pastebin上)这段代码没有明显的错误,也没有明显的原因说明计时器的勾号事件不会运行。调试器通知没有那么有用,.NET framework一般都支持线程。如果是UI线程,则NotifyIcon也不会再工作。缺少的是创建此表单实例并调用Application.Run(),如果它不是Program.csI中的样板代码可能会有问题。我在开始的文章中添加了我的设计器文件和Program.cs(请参见更新1和2)。这也是我的第一个想法。我使用timer1.Stop()和timer1.Start()完成了这项工作,但结果是一样的。我想我是在某种程度上停止计时器代码再次运行,所以我决定让它一直滴答作响,但只在适当的时候从我的_timeLeft变量中减去。我明白你的观点,但我相信下面的行(在Form1的构造函数中)会自动将其转换为秒:“timer1.Interval=1000;//秒"我只是试着输入你的代码,但是线程退出时结果仍然一样。唯一的小问题是,即使我将它设置为不显示在任务栏上,当它最小化时,它会显示在Windows开始按钮后面的左下角。我的任务栏会自动隐藏,因此我可以看到应用程序的标题当我在程序之间切换时,我只是通过设置Opa解决了这个问题
private void timer1_Tick(object sender, EventArgs e)
    {
        // count down
        if (_timeLeft > 0)
            _timeLeft = _timeleft - 1000; //Since your interval is 1s subtract that.

        label2.Text = ((_timeLeft / 1000) / 60).ToString() + " minutes left"; // convert back to minutes
        notifyIcon1.Text = ((_timeLeft / 1000) / 60).ToString() + " minutes left"; 
        Console.WriteLine(((_timeLeft / 1000) / 60).ToString() + " minutes left"); 

        // if time ran out --> show the window
        if (_timeLeft <= 0)
        {
            this.WindowState = FormWindowState.Normal;
        }
    }
//Debugging version of GetRanomdTime
    private void GetRandomTime()
    {
        //Random rand = new Random((int)DateTime.Now.Ticks);

        _timeleft = 1 * 60 * 1000;
    }
private void Form1_Resize_1(object sender, EventArgs e)
        {
            /*if (WindowState == FormWindowState.Minimized)
            {
                this.Hide(); // only show in tray icon, not in task bar
            }
            else if (WindowState == FormWindowState.Normal)
            {
                this.Show();
            }*/
        }