【发布时间】:2011-12-18 09:16:09
【问题描述】:
我正在创建一个倒计时计时器,允许用户选择一个有效时间,一旦倒计时归零,它就会播放声音。
我从System.Timers 命名空间实例化了一个计时器,并将其Interval 设置为1 秒。我将用户指定的时间转换为秒,并在每次Timer.Elapsed 函数命中时将该值递减1。一旦它达到零,这意味着倒计时已经到零,这意味着是时候播放声音了。
但是,只要它没有达到零,我就会将时间值减少1,并且我还想使用progressbar.Increment 函数增加ProgressBar。
不幸的是,每当我这样做时,它都会给我一个与多线程问题有关的异常。我知道出了什么问题,但我不知道如何解决它。我需要在新线程上启动timer.Elapsed 函数吗?
错误是:
跨线程操作无效:已访问控件“CountdownProgress” 来自创建它的线程以外的线程。
此外,我们也欢迎任何有关更好编程习惯的提示。 非常感谢!
代码如下:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Timers;
using System.Media;
using System.Diagnostics;
using System.Threading;
namespace WindowsFormsApplication1
{
public partial class Form_CDA : Form
{
public Form_CDA()
{
InitializeComponent();
}
private bool m_CountdownActive; // declare global variables and instantiate timer.
private bool m_Cancelled;
public decimal seconds;
public decimal minutes;
public decimal hours;
public decimal time;
public System.Timers.Timer timer = new System.Timers.Timer();
private void Form_CDA_Load(object sender, EventArgs e)
{
m_Cancelled = false;
timer.AutoReset = false;
timer.Interval = 0;
m_CountdownActive = false;
richTextBox1.Text = "Hello, please select an hour between 0 and 100, a minute between 0 and 59, and a second between 0 and 59. The countdown timer will play a sound when finished.";
btn_Cancel.Enabled = false;
seconds = 0;
minutes = 0;
hours = 0;
time = 0;
m_StatusBar.Text = "Program properly loaded, waiting for user input"; // initialize variables.
}
private void btn_SetCountdown_Click(object sender, EventArgs e)
{
seconds = numUpDown_Seconds.Value;
minutes = numUpDown_Minutes.Value;
hours = numUpDown_Hours.Value;
time = (hours * 3600) + (minutes * 60) + seconds; // calculate the total time in seconds.
if (time != 0) // if time is not zero, start timer and set up event handler timer.elapsed.
{
timer.Interval = 1000;
timer.AutoReset = true;
timer.Start();
timer.Elapsed += new ElapsedEventHandler(timer_Elapsed);
CountdownProgress.Maximum = (int)time;
CountdownProgress.Minimum = 0;
CountdownProgress.Value = 0;
}
else
{
m_StatusBar.Text = "Invalid selection of times. Try again.";
return;
}
DateTime dt = DateTime.Now;
dt.AddSeconds((double)time);
Label_Countdown.Text = "Finishing time: " + dt.ToString(); // display end time to user.
m_CountdownActive = true;
btn_Cancel.Enabled = true;
btn_SetCountdown.Enabled = false;
numUpDown_Hours.Enabled = false;
numUpDown_Minutes.Enabled = false;
numUpDown_Seconds.Enabled = false; // disable controls.
m_Cancelled = true;
m_StatusBar.Text = "Timer set to " + numUpDown_Hours.Value.ToString() + " hours, " + numUpDown_Minutes.Value.ToString() + " minutes, " + numUpDown_Seconds.Value.ToString() + " seconds.";
}
void timer_Elapsed(object sender, ElapsedEventArgs e)
{
if (time == 0)
{
m_StatusBar.Text = "Countdown Finished";
SoundPlayer soundPlayer = new SoundPlayer(@"C:\Users\marupakuuu\Desktop\New stuff\doorbell.wav");
soundPlayer.Play(); // play sound.
timer.Stop();
return;
}
else
{
time = time - 1;
CountdownProgress.Increment(1); // exception occurs here; multithreading issues.
}
}
private void btn_Cancel_Click(object sender, EventArgs e)
{
// if user wishes to stop the countdown to start a new one.
m_Cancelled = true;
m_CountdownActive = false;
btn_SetCountdown.Enabled = true;
numUpDown_Seconds.Value = 0;
numUpDown_Minutes.Value = 0;
numUpDown_Hours.Value = 0;
numUpDown_Hours.Enabled = true;
numUpDown_Minutes.Enabled = true;
numUpDown_Seconds.Enabled = true;
btn_Cancel.Enabled = false;
m_StatusBar.Text = "Countdown cancelled";
}
}
}
【问题讨论】:
标签: c# winforms multithreading progress-bar