如何在C#中停止线程?

3

信息:我正在使用Visual Studio 2017中的C#创建游戏

我该如何停止音乐线程?即使来自不同的窗体,这是否可能? 我使用了以下代码创建在后台播放音乐的线程:

MediaPlayer bg;

public void main()
{
    IntializeComponent();
    Bg_music();
}

private void Bg_music()
{
    new System.Threading.Thread(() =>
    {
        bg = new System.Windows.Media.MediaPlayer();
        bg.Open(new System.Uri(path + "Foniqz_-_Spectrum_Subdiffusion_Mix_real.wav"));
        bg.Play();
    }).Start();                        
}

当我尝试使用这段代码停止线程时,它会停止当前打开的窗口,但音乐/线程仍会继续播放音乐。
bg.Dispatcher.Invoke(() =>
{
    bg.Close();
});

同时这个方案没有奏效

bg.Dispatcher.Invoke(() =>
{
    bg.Stop();
});

8
首先,不再使用线程,这些已被TPL的“Task”取代。相比手动管理线程,“Task”具有许多优点和改进。 - Liam
可能是如何中止/取消TPL任务?的重复问题。 - Liam
1
完全不需要使用线程。Play() 不会阻塞用户界面。 - Panagiotis Kanavos
1
@Miicat 你想做什么?Play()不会阻塞,而且最好使用MediaPlayerElement标记。请查看使用MediaPlayer播放音频和视频标记。 - Panagiotis Kanavos
1
@Liam Play不会阻塞。不需要任务。问题有点...不清楚。 - Panagiotis Kanavos
显示剩余9条评论
2个回答

2

假设您确实需要一个后台线程(因为WPF上的MediaPlayer是非阻塞的),您可以使用以下C#路径之一:

  1. Use Cancelation Token & Tasks:

        MediaPlayer bg;
    readonly CancellationTokenSource tokenSource = new CancellationTokenSource();
    public MainWindow()
    {
        InitializeComponent();
        Bg_music();
    }
    
    private void Bg_music()
    {
    
        Task.Run(() =>
        {
            bg = new MediaPlayer();
            bg.Open(new Uri(@"D:\Songs\201145-Made_In_England__Elton_John__320.mp3"));
            bg.Play();
            bg.Play();
            while (true)
            {
                if (tokenSource.Token.IsCancellationRequested)
                {
                    bg.Stop();
                    break;
                }
            }
    
        }, tokenSource.Token);
    
    }
    
    private void ButtonBase_OnClick(object sender, RoutedEventArgs e)
    {
           tokenSource.Cancel();
    }
    

    }

或者

  1. 使用事件通过任务进行通信。(不要再使用线程,现在有了任务)

如果同时播放其他声音,它是否会继续播放音乐?这是我最初解决如何同时播放两个声音的代码链接:https://stackoverflow.com/questions/50425310/how-i-can-play-two-sounds-simultaneously-in-c-sharp - Miicat
我怎么可以阻止它来自其他表单? - Miicat

-1

跨线程对象访问可能会很棘手。

如果您在UI线程之外的另一个线程中创建了MediaPlayer实例,则在UI线程内访问此对象将引发InvalidOperationException,因为该对象不属于UI线程。

    private void Bg_music()
    {
        bg = new System.Windows.Media.MediaPlayer();
        new System.Threading.Thread(() =>
        {
            bg.Dispatcher.Invoke(()=>{
                bg.Open(new System.Uri(path + "Foniqz_-_Spectrum_Subdiffusion_Mix_real.wav"));
                bg.Play();
            });

        }).Start();                        
    }

现在,当您在UI线程中调用MediaPlayer时,您不必使用Dispatcher来停止它。
编辑:即使实现的方法不是最佳实践,仍然值得回答以提供一些理论信息。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接