1

我的项目的重点是创建一个交互式教程。我正在播放声音剪辑,并且在声音剪辑期间的某些时候,我希望执行某些操作(例如,突出显示按钮)。我想出了一个解决方案,但我觉得它占用了很多 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();

下面的代码是我所能得到的线程,我很难从步骤 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();

一旦线程通过,它将返回到线程的开头并执行 thread.sleep(5000)。我不确定如何通过线程更改每次旋转的睡眠时间和动作。任何帮助将不胜感激,我希望我的问题清晰易懂。我正在使用 Visual Studio 2012、C#、WPF。

4

3 回答 3

0

我认为最简单的方法是使用async

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

    await Task.Delay(1000);
    Button_Logistics.Visibility = Visibility.Visible;

    await Task.Delay(500);
    Image_SAP_Main.Visibility = Visibility.Hidden;
    Image_SAP_Main_Logistics.Visibility = Visibility.Visible;
    Button_Logistics.Visibility = Visibility.Hidden;

    await Task.Delay(500);
    Button_MMBE.Visibility = Visibility.Visible;

    await Task.Delay(500);
    Image_SAP_Main_Logistics.Visibility = Visibility.Hidden;
    Button_MMBE.Visibility = Visibility.Hidden;
    Image_SAP_MMBE.Visibility = Visibility.Visible;
}

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

于 2013-06-12T11:58:48.423 回答
0

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

所以......因为你有一个定义的动作序列,你可以这样写:

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();

线程将继续执行语句,在Sleep调用处暂停,执行各种步骤方法,然后退出。

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

于 2013-06-12T01:59:12.067 回答
0

可以通过使用线程和 Thread.Sleep 来解决按顺序分离多个事物并在某些部分之间产生延迟的问题,但这可能会带来问题,因为它引入了明确的等待,更不用说在等待期间将线程绑定在一起了。

微软引入了任务系统作为直接线程访问的事实上的高级替代。

一个例子是:

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();

与 Thread.Sleep 相比,这种方法有许多优点,任务被安排并为您处理线程管理,任务还具有组合功能(ContinueWith 等),请参阅文档以获取更多信息。

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

于 2013-06-12T03:14:03.327 回答