播放 .wav 时的 C# 消息队列

标签 c# .net wav

我有一个程序,当单击按钮时可以同步播放三个 .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/

相关文章:

c# - 使用 C# 从 DataTable 创建 HTML

android - 在Android上将FloatArray音频缓冲区保存到WAV文件

audio - 如何将音频x-wav文件转换为常规wav文件

c# - N-Hibernate 中的长字符串与 Oracle 导致错误

java - 在 for 循环中获取枚举的序数 [c#]

.net - 为什么NET Core 2.0中UseAuthentication必须在UseMvc之前

c# - 为什么 ValidateRequest ="true"不足以预防 XSS?

c# - 找不到 C# MVC 模型属性的定义

c# - Dictionary<string, object>-to-BsonDocument 转换省略 _t 字段

audio - 这2个wav文件有什么区别?