我正在开发基本的音频播放器,我想根据歌曲的进度来更新一些GUI元素。
在我的表单旁边,我使用一个AudioPlayer类,该类在创建的Form上包含一个引用。
在playAudio函数中,我想启动一个计时器,该计时器经过后应调用updateCurrTime。 (供参考:我正在使用NAudio)
调用计时器的函数:
public bool playAudio()
{
if (waveOutDevice.PlaybackState == PlaybackState.Playing)
{
waveOutDevice.Pause();
timer.Enabled = false;
return false;
}
else if(waveOutDevice.PlaybackState == PlaybackState.Paused)
{
waveOutDevice.Play();
timer.Enabled = true;
return true;
}
else if(waveOutDevice.PlaybackState == PlaybackState.Stopped)
{
initPlayer(mu_path);
waveOutDevice.Play();
timer.Enabled = true;
return true;
}
return false;
}
以及使用以下命令更新我的表单的函数:
public void updateCurrTime()
{
while (waveOutDevice.PlaybackState == PlaybackState.Playing)
{
form1_ref.curr_time = (int)audioFileReader.CurrentTime.TotalSeconds;
}
}
我这样定义了计时器:
timer = new Timer();
timer.Elapsed += new ElapsedEventHandler(OnTimedEvent);
timer.Interval = 100;
}
和这样的OnTimedEvent:
private static void OnTimedEvent(object source, ElapsedEventArgs e)
{
self_ref.updateCurrTime();
}
我将getter / setter结构用于标签文本:
public int curr_time
{
get { return Convert.ToInt32(this.l_t_curr.Text); }
set { this.l_t_curr.Text = value.ToString() + "s"; }
}
我的问题是,我得到一个错误,因为表单是在另一个线程上创建的。我做了研究,但是我不了解如何在我的情况下实现BackGroundWorker或其他解决方案。
答案 0 :(得分:0)
借助Julo的提示,我得以解决此问题。
public void updateCurrTime()
{
MethodInvoker methodInvokerDelegate = delegate ()
{ form1_ref.l_t_curr.Text = audioFileReader.CurrentTime.TotalSeconds.ToString(); };
//form1_ref.curr_time = (int)audioFileReader.CurrentTime.TotalSeconds;
//This will be true if Current thread is not UI thread.
if (form1_ref.InvokeRequired)
form1_ref.Invoke(methodInvokerDelegate);
else
methodInvokerDelegate();
}
答案 1 :(得分:0)
要从另一个线程更新GUI,您需要使用Invoke
或BeginInvoke
。
示例:
private void GuiUpdate(object sender, EventArgs e)
{
if (this.InvokeRequired)
{
this.BeginInvoke((MethodInvoker)delegate
{
GuiUpdate(sender, e);
});
return;
}
// put here GUI updating code
}
Invoke
或BeginInvoke
之间的差异为:
Invoke
停止执行当前线程,直到被调用的函数结束,BeginInvoke
时,启动线程将继续运行而不会中断。当您需要函数结果或优先级更新时,请使用Invoke
。否则,最好使用BeginInvoke
。