我正在制作秒表,我想在某种竞争中使用。我想通过点击按钮1启动我的秒表,以便播放第一个wav文件并在秒表开始之后。但秒表无法启动。这就是我到现在为止所做的。
Stopwatch sw = new Stopwatch();
private void button1_Click(object sender, EventArgs e)
{
new System.Threading.Thread(testMethod).Start();
}
private void testMethod(object obj)
{
System.Media.SoundPlayer sp = new System.Media.SoundPlayer(@"D:\...\something.wav");
sp.Play();
}
void OnSoundPlayOver(object sender, EventArgs e)
{
timer1.Start();
timer2.Start();
sw.Start();
}
答案 0 :(得分:0)
如果您的要求是:
以下代码是如何使上述要求有效的BASIC示例。它利用SoundPlayer的PlaySync方法,BackgroundWorker(将标签上的值更新为经过的秒数)和实际记录经过时间的秒表。它绝对不是实现这一目标的最佳方式,但它应该为您提供一个起点。
需要注意的一点是,您无法从与创建标签的线程(通常是UI线程)不同的线程更新Label。因此,如果您尝试从另一个线程更新标签的文本,则需要使用标签.Invoke方法(请参阅下面代码中的 ThreadSafeUpdateLabel 方法)。
此代码未考虑有人垃圾邮件点击“开始”按钮的情况(它只是单击您播放的声音次数),并且只要获取声音,当您单击“开始”按钮时,UI就会冻结玩。我将把这些问题作为代码的自然扩展来解决。
无论如何,在代码上:
private Stopwatch _timer = new Stopwatch();
private BackgroundWorker _worker;
private void btnStop_Click(object sender, EventArgs e)
{
CancelExistingBackgroundWorker();
_timer.Stop();
}
private void btnStart_Click(object sender, EventArgs e)
{
CancelExistingBackgroundWorker();
_timer.Reset();
UpdateLabel(0);
_worker = new BackgroundWorker() { WorkerSupportsCancellation = true };
_worker.DoWork += (a, b) =>
{
while (true)
{
if ((a as BackgroundWorker).CancellationPending) return;
ThreadSafeUpdateLabel();
Thread.Sleep(100);
}
};
var soundPlayer = new SoundPlayer("wavfile.wav");
soundPlayer.PlaySync();
_timer.Start();
_worker.RunWorkerAsync();
}
private void ThreadSafeUpdateLabel()
{
if (lblElapsed.InvokeRequired)
{
lblElapsed.Invoke(new Action(() => ThreadSafeUpdateLabel()));
}
else
{
UpdateLabel(_timer.Elapsed.TotalSeconds);
}
}
private void UpdateLabel(double seconds)
{
lblElapsed.Text = seconds.ToString();
}
private void CancelExistingBackgroundWorker()
{
if (_worker != null)
{
_worker.CancelAsync();
_worker.Dispose();
}
}