从参考开始按计时器设置表单标签文本

时间:2018-12-23 14:26:10

标签: c# multithreading forms winforms

我正在开发基本的音频播放器,我想根据歌曲的进度来更新一些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或其他解决方案。

2 个答案:

答案 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,您需要使用InvokeBeginInvoke

示例:

private void GuiUpdate(object sender, EventArgs e)
{
  if (this.InvokeRequired)
  {
    this.BeginInvoke((MethodInvoker)delegate
    {
      GuiUpdate(sender, e);
    });
    return;
  }

  // put here GUI updating code
}

InvokeBeginInvoke之间的差异为:

  • Invoke停止执行当前线程,直到被调用的函数结束,
  • 使用BeginInvoke时,启动线程将继续运行而不会中断。

当您需要函数结果或优先级更新时,请使用Invoke。否则,最好使用BeginInvoke