0

上下文:我正在通过媒体元素播放音乐,并使用滑块显示歌曲所在的位置。出于显而易见的原因,该更新是在后台工作人员中完成的。

private void bgPlay_DoWork(object sender,DoWorkEventArgs e)
    {

        while (isMediaPlaying)
        {
            this.Dispatcher.Invoke((Action)(() =>
            {
                timelineSlider.Value = mediaElement1.Position.TotalMilliseconds;
            }));

        }
    }

    private void Library_MouseDoubleClick(object sender, MouseButtonEventArgs e)
    {
        try
        {
            mediaElement1.Stop();
            isMediaPlaying = false;
            mediaElement1.Source = new Uri(songData[Library.SelectedIndex].Location);
            mediaElement1.Volume = (double)volumeSlider.Value;

            mediaElement1.Play();

            isMediaPlaying = true;

            bgPlay.RunWorkerAsync();
        }
        catch(Exception ex) {
            F.MessageBox.Show(ex.ToString());
        }
    }

当我播放一首歌曲,然后双击另一首歌曲时,后台工作人员仍在循环并引发异常,因为它bgPlay.RunWorkerAsync();在前一个实例完成之前到达。我尝试使用 isMediaPlaying 布尔值来告诉后台工作人员何时退出循环,但主线程bgPlay.RunWorkerAsync();在完成之前到达。

4

1 回答 1

0

当一个人几乎没有开始使用线程编程时,你正在遭受一个常见的错误,这是一种竞争条件

我建议像这样重写代码:

private static String threadingLock = "";

private void bgPlay_DoWork(object sender,DoWorkEventArgs e)
    {

        while (true)
        {
            lock(threadingLock) {
                if(!isMediaPlaying)
                    break;
            }
            this.Dispatcher.Invoke((Action)(() =>
            {
                timelineSlider.Value = mediaElement1.Position.TotalMilliseconds;
            }));

        }
    }

    private void Library_MouseDoubleClick(object sender, MouseButtonEventArgs e)
    {
        try
        {
            lock(threadingLock) {
                isMediaPlaying = false;
            }
            mediaElement1.Stop();

            mediaElement1.Source = new Uri(songData[Library.SelectedIndex].Location);
            mediaElement1.Volume = (double)volumeSlider.Value;

            mediaElement1.Play();

            isMediaPlaying = true;

            bgPlay.RunWorkerAsync();
        }
        catch(Exception ex) {
            F.MessageBox.Show(ex.ToString());
        }
    }

作为一个友好的提示,Thread.sleep(200)在调用滑块上的更新之前添加一个。它将减少 CPU 使用率,而不会影响应用程序的功能。

于 2013-01-22T23:38:37.173 回答