>上下文:我正在通过媒体元素播放音乐,并使用滑块显示歌曲中的位置。出于显而易见的原因,该更新是在后台工作者中完成的。
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();
。我尝试使用 isMediaPlay bool 告诉后台工作人员何时退出循环,但主线程在完成之前到达bgPlay.RunWorkerAsync();
。
当一个人刚刚开始使用线程编程时,你遇到了一个常见的错误,这是一种竞争条件
我建议像这样重写代码:
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 使用率,而不会影响应用程序的功能。