【发布时间】:2015-11-23 15:35:17
【问题描述】:
所以基本上,我正在创建音乐软件,并且希望能够在必要时暂停/停止歌曲。但是,当歌曲播放时,它不允许使用表单上的任何控件,并且“KeyDown”事件似乎也没有影响,因此在歌曲结束之前我无法停止歌曲。
我尝试使用“线程”类的实例来执行此操作,但问题是我需要在表单上使用某些“标签”控件,这似乎很难从另一个线程中完成。
这是我的“播放”代码的要点。
Sound[] notes = song.Sounds;
double seconds = 0;
foreach (Sound sound in notes)
{
seconds += (double)sound.NoteType.GetDuration(tempo) / 1000;
}
timeleft = seconds;
lblSecondsLeft.Text = timeleft + "";
double length = notes.Length;
double thing = (100 / length);
double otherthing = Math.Round(thing);
sounds = notes;
double progress = 0;
for (int i = 0; i < notes.Length; i++)
{
Sound sound = notes[i];
lblTempo.Text = tempo.ToString();
string note = sound.Note.ToString();
lblNote.Text = note;
progress += thing;
lblProgress.Text = progress + "%";
seconds -= (double)sound.NoteType.GetDuration(tempo) / 1000;
lblSecondsLeft.Text = seconds + " seconds left";
sound.PlaySound(song.Channel);
}
【问题讨论】:
-
好吧,您在 UI 线程上同步运行所有内容 - 当然不能使用 UI。
Sound类(不管是什么)有异步 API 吗?不过,逐个音符演奏可能效果并不好…… -
我想说的是我之前试图在另一个线程中运行这段代码,因此它已经是异步的。
-
嗯,你不会摆脱使用不同的线程。但是如果你使用 Invoke 从另一个线程访问控件是没有问题的。
-
嗯,最简单的方法是将演示代码与实际播放分开。然后你可以使用例如
IProgress<T>根据需要发布任何 UI 更新。尽管无论如何您可能希望使用基于拉取的方法,因为您当前的方法是发布太多更新(当注释很短时)或太少(当注释很长时)。读取当前状态和更新 UI 的计时器可能会更好。 -
添加到@Luaan 最后的评论,您可以添加事件
NextNote来更新进度(例如显示当前播放的音符以及还剩多少音符/秒)和事件Started/Finished(用于明显的原因)到您的模型(用于播放歌曲)。
标签: c# multithreading winforms