C# 如何使用一个线程来执行多个计时操作,而不是使用多个计时器

C# 如何使用一个线程来执行多个计时操作,而不是使用多个计时器,c#,wpf,timer,thread-sleep,C#,Wpf,Timer,Thread Sleep,我的项目的重点是创建一个交互式教程。我正在播放一段声音片段,在播放声音片段的特定时间,我希望采取某些动作。突出显示一个按钮。我已经想出了一个解决方案,但我觉得它正在消耗大量的CPU。我提出的解决方案是为声音剪辑期间发生的每个动作设置每个计时器。如果我开始为50个不同的动作制作50个不同的计时器,这将产生50个不同的线程,那么我预计最终会对CPU造成影响 下面是我当前使用这些计时器的代码片段 private void Label_FindingPart_MouseDoubleClick(objec

我的项目的重点是创建一个交互式教程。我正在播放一段声音片段,在播放声音片段的特定时间,我希望采取某些动作。突出显示一个按钮。我已经想出了一个解决方案,但我觉得它正在消耗大量的CPU。我提出的解决方案是为声音剪辑期间发生的每个动作设置每个计时器。如果我开始为50个不同的动作制作50个不同的计时器,这将产生50个不同的线程,那么我预计最终会对CPU造成影响

下面是我当前使用这些计时器的代码片段

private void Label_FindingPart_MouseDoubleClick(object sender, MouseButtonEventArgs e)
    {
        sound.Source = new Uri(@"C:\SomeSound.wav");
        sound.Position = TimeSpan.Zero;  
        sound.Play();

        Timer_Logistics_Button(1000);
        Timer_Logistics_Window(1500);
        Timer_MMBE_Button(2000);
        Timer_MMBE_Window(2500);
    }
    //Timer initalized
    private void Timer_Logistics_Button(int interval_length)
    {
        System.Timers.Timer aTimer = new System.Timers.Timer();
        aTimer.AutoReset = false;
        aTimer.Elapsed += new ElapsedEventHandler(On_Timer_Logistics_Button);
        aTimer.Interval = interval_length;
        aTimer.Enabled = true;
    }
    //Action when the Elapsed event is raised.
    private void On_Timer_Logistics_Button(object source, ElapsedEventArgs e)
    {
        Dispatcher.BeginInvoke((Action)delegate()
        {
            Button_Logistics.Visibility = Visibility.Visible;
        });

    }
    //Timer initalized
    private void Timer_Logistics_Window(int interval_length)
    {
        System.Timers.Timer aTimer = new System.Timers.Timer();
        aTimer.AutoReset = false;
        aTimer.Elapsed += new ElapsedEventHandler(On_Timer_Logistics_Window);
        aTimer.Interval = interval_length;
        aTimer.Enabled = true;
    }
    //Action when the Elapsed event is raised.
    private void On_Timer_Logistics_Window(object source, ElapsedEventArgs e)
    {
        Dispatcher.BeginInvoke((Action)delegate()
        {
            Image_SAP_Main.Visibility = Visibility.Hidden;
            Image_SAP_Main_Logistics.Visibility = Visibility.Visible;
            Button_Logistics.Visibility = Visibility.Hidden;

        });

    }
    //Timer initalized
    private void Timer_MMBE_Button(int interval_length)
    {
        System.Timers.Timer bTimer = new System.Timers.Timer();
        bTimer.AutoReset = false;
        bTimer.Elapsed += new ElapsedEventHandler(On_Timer_MMBE_Button);
        bTimer.Interval = interval_length;
        bTimer.Enabled = true;
    }
    //Action when the Elapsed event is raised.
    private void On_Timer_MMBE_Button(object source, ElapsedEventArgs e)
    {
        Dispatcher.BeginInvoke((Action)delegate()
        {
            Button_MMBE.Visibility = Visibility.Visible;
        });
    }
    //Timer initalized
    private void Timer_MMBE_Window(int interval_length)
    {
        System.Timers.Timer bTimer = new System.Timers.Timer();
        bTimer.AutoReset = false;
        bTimer.Elapsed += new ElapsedEventHandler(On_Timer_MMBE_Window);
        bTimer.Interval = interval_length;
        bTimer.Enabled = true;
    }
    //Action when the Elapsed event is raised.
    private void On_Timer_MMBE_Window(object source, ElapsedEventArgs e)
    {
        Dispatcher.BeginInvoke((Action)delegate()
        {
            Image_SAP_Main_Logistics.Visibility = Visibility.Hidden;
            Button_MMBE.Visibility = Visibility.Hidden;
            Image_SAP_MMBE.Visibility = Visibility.Visible;
        });
    }
我的另一个想法是创建一个线程,并让它与sound.play同时启动。这一个线程将有多个thread.sleep语句用于每个操作之间的等待时间。因此,回想起来,情况是这样的:

    Step A: Play();
    Step B: Thread.Start();
    Step C: Thread.sleep(1000);
    Step D: ACTION;
    Step E: Thread.sleep(500);
    Step F: ACTION;
    Step G: Thread.sleep(1200);
    Step H: ACTION;
    Step I: Thread.Stop();
Thread Tutorial_Thread = new Thread(() => 
    {
        Thread.Sleep(1000);
        this.Dispatcher.BeginInvoke(() => do_step_d());
        Thread.Sleep(500);
        this.Dispatcher.BeginInvoke(() => do_step_f());
        Thread.Sleep(1200);
        this.Dispatcher.BeginInvoke(() => do_step_h());
    });
Tutorial_Thread.Start();
下面的代码是我在线程方面所能得到的,我从步骤D到步骤E经历了一段艰难的时间。我还需要找出如何正确地停止我的线程。下面的代码是我能够化脓的代码:

     System.Threading.Thread Tutorial_Thread = new System.Threading.Thread(new System.Threading.ThreadStart(
        delegate()
        {
            // Do the work here.
            Thread.Sleep(5000);


            this.Dispatcher.BeginInvoke(new Action(
            delegate()
            {
                // Invoke any updates to the GUI here.
                Button_Logistics.Visibility = Visibility.Visible;

            }
         ));
        }
         ));
        sound.Play();
        Tutorial_Thread.Start();
一旦线程完成,它将返回到线程的开头并执行该线程。sleep5000。我不知道如何更改线程中每次旋转的睡眠时间和动作。任何帮助都将不胜感激,我希望我的问题清楚易懂。
我使用的是Visual Studio 2012、C、WPF。

线程执行代码然后退出,除非代码循环,否则它不会循环。在您发布的示例中,线程等待5秒钟,更改按钮的可见性,然后退出

所以。。。由于您有一个已定义的操作序列,因此可以这样编写:

    Step A: Play();
    Step B: Thread.Start();
    Step C: Thread.sleep(1000);
    Step D: ACTION;
    Step E: Thread.sleep(500);
    Step F: ACTION;
    Step G: Thread.sleep(1200);
    Step H: ACTION;
    Step I: Thread.Stop();
Thread Tutorial_Thread = new Thread(() => 
    {
        Thread.Sleep(1000);
        this.Dispatcher.BeginInvoke(() => do_step_d());
        Thread.Sleep(500);
        this.Dispatcher.BeginInvoke(() => do_step_f());
        Thread.Sleep(1200);
        this.Dispatcher.BeginInvoke(() => do_step_h());
    });
Tutorial_Thread.Start();
线程将继续执行语句,在睡眠调用时暂停,执行各种步骤方法,然后退出


这当然是一个过于简单的例子。与其编写一段只执行单个序列的静态代码,并为每个不同的序列编写类似的代码,不如找出一个可以将事件序列排队的调度系统。。。可能使用mike z的建议来处理计时。

通过使用线程和线程,可以解决按顺序旋转多个事物,并在某些片段之间延迟。睡眠可能会有问题,因为它引入了明确的等待,更不用说它会在等待期间将线程连接起来

微软推出的任务系统实际上是直接线程访问的高级替代品

例如:

Play();
Task.Factory.StartNew(async () =>
    {
        await Task.Delay(1000);
        action_1();
        await Task.Delay(500);
        action_2();
        await Task.Delay(1200);
        action_3();
    });

// Task start returns immediately
Console.ReadLine();
与线程相比,这种方法有许多优点。睡眠、任务调度和线程管理由您负责,任务还具有连续的合成功能等。有关更多信息,请参阅文档


不过,最大的优点是,通过使用新的C async/await使任务本身成为一个异步方法,每次等待延迟时,底层线程都可以用于其他工作,因此不会使系统缺少线程。

我认为最简单的方法是使用异步:


如果需要停止它,只需使用CancellationTokenSource并将其CancellationToken传递到所有Task.Delay调用中。

您应该只使用多个Dispatchers,而不是调用回UI线程。它将只使用一个线程,即调度程序的线程来服务回调。旁注:计时器,尤其是睡眠,是同步两个或多个事件序列的不可靠方法。双方都不保证按时完工。您最好定期检查应该发生的事情,即与教程场景相关的50毫秒,而不是依赖计时器/睡眠在非常特定的时刻触发。