我有一个程序,当单击按钮时可以同步播放三个 .wav 文件。问题是,即使我在单击处理程序的第一条指令上禁用按钮,如果在播放声音时使用单击,其他鼠标单击事件也会排队,然后在播放完成时执行。我怎样才能避免这种情况?
这是我的点击处理程序,playSnippet_P1,2,3 以不同的顺序播放三个音频文件:
void btnPlay_Click(object sender, EventArgs e)
{
btnPlay.Enabled = false;
this.Refresh();
//play a snippet for the current passage
switch (myProgram.condition)
{
case 1:
playSnippet_P1();
break;
case 2:
playSnippet_P2();
break;
case 3:
playSnippet_P3();
break;
default:
if (myProgram.debug)
{
MessageBox.Show("Error(frmPassage): Invalid condition set: " + myProgram.condition);
}
break;
}
//leave this phase once final passage is finished
if (snipsPlayed >= (myProgram.snipCount_1
+ myProgram.snipCount_2
+ myProgram.snipCount_3))
{
myProgram.phaseController.runNextPhase();
}
//reset the form to show text for next passage
if (snipsPlayed >= (getSnipCount(1) + getSnipCount(2)))
currentPassage = 2;
else if (snipsPlayed >= getSnipCount(1))
currentPassage = 1;
else
currentPassage = 0;
lblTitle.Text = "Passage " + randPOrder[currentPassage].ToString();
btnPlay.Enabled = true;
}
private void playSnippet_P1()
{
snipsPlayed++;
int cSnipCount = getCSnipCount();
int snipNum = (snipsPlayed % cSnipCount);
int subNum = getSubNum(snipsPlayed);
if (snipNum == 0)
snipNum = cSnipCount;
int rPassage = randPOrder[currentPassage];
//play "Next question is for..."
JE_SP.playSound(Application.StartupPath
+ "\\res\\audio\\next\\Next" + subNum.ToString()
+ ".wav", true);
//play snippet
JE_SP.playSound(Application.StartupPath
+ "\\res\\audio\\passages\\Snip" + rPassage.ToString()
+ "-" + snipNum.ToString()
+ ".wav", true);
//play question
JE_SP.playSound(Application.StartupPath
+ "\\res\\audio\\passages\\Q" + rPassage.ToString()
+ "-" + snipNum.ToString()
+ ".wav", true);
string[] writeMe =
{
rPassage.ToString(),
"\\res\\audio\\passages\\Snip" + rPassage.ToString()
+ "-" + snipNum.ToString(),
"\\res\\audio\\passages\\Q" + rPassage.ToString()
+ "-" + snipNum.ToString(),
subNum.ToString(),
myProgram.condition.ToString()
};
JE_Log.logData(writeMe, "\t", myProgram.groupFile);
}
最佳答案
此行为的更简单重现:
private void button1_Click(object sender, EventArgs e) {
button1.Enabled = false;
System.Threading.Thread.Sleep(1000);
button1.Enabled = true;
}
问题在于,UI 线程繁忙时记录的鼠标单击会进入消息队列并卡在那里,直到事件处理程序完成。当发生这种情况时,该按钮已再次启用,允许 Click 事件再次运行。
解决这个问题很麻烦,并且需要付出在工作线程上运行代码的代价。一个可能的好修复方法是在重新启用按钮之前清除消息队列并删除所有鼠标消息,但这在 Winforms 中并不容易。代码实际上在那里,但它是内部的。一个真正务实的解决方案可能会给我带来麻烦,但安全有效:
private void button1_Click(object sender, EventArgs e) {
button1.Enabled = false;
System.Threading.Thread.Sleep(1000);
Application.DoEvents();
if (!button1.IsDisposed) button1.Enabled = true;
}
关于播放 .wav 时的 C# 消息队列,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4392712/