GUI 启动时控制台 "Hangs"

Console "Hangs" when GUI launches

在我开始之前,我想为我在问这个问题时可能表现出的任何...白痴道歉,我正在尝试学习 C# 来自 Java,并且只想直接跳进去!

我正在开发一个旨在通过控制台接收命令的项目,例如 "play batman begins" 它将开始播放电影《蝙蝠侠:侠影之谜》。它还接受音乐等命令。通过此设置,我的目标是让它语音控制,所以我并不真正关心使用 GUI 而不是控制台。当我让程序播放电影时,它会加载一个没有边框、没有内容的 GUI window,它使用的构造函数是:

public MainWindow(MediaPlayer player)
{
     InitializeComponent();
     VideoDrawing drawing = new VideoDrawing { Rect = new Rect(0, 0, 800, 600), Player = player };
     DrawingBrush brush = new DrawingBrush(drawing);
     Background = brush;
}

MediaPlayer 由主函数控制(目前)。我加载视频的代码 运行 是:

MediaPlayer mp = new MediaPlayer();
mp.Open(new Uri("C:\test.mp4", UriKind.RelativeOrAbsolute));

VideoDrawing vidDrawing = new VideoDrawing();
vidDrawing.Rect = new Rect(0, 0, 100, 100);
vidDrawing.Player = mp;

DrawingBrush DBrush = new DrawingBrush(vidDrawing);
videoPanel = new MainWindow(mp); // GUI panel to play the video on, constructor is listed above

play();
new System.Windows.Application().Run(videoPanel);

由于我是 C# 的新手,我使用 GUI 的方法是启动一个新的 WPF 项目,创建 GUI 并编写代码,然后复制粘贴 xaml和 cs 文件到我的项目中(因为我是菜鸟,对不起)。可能这是导致问题的原因。

此代码(大部分)工作正常。当我 运行 我的程序时,它加载视频文件,打开 Window,并在播放声音的同时在屏幕上播放视频。然而,当它开始播放视频时,GUI "hangs" 并且不接受任何输入的 OR 输出,但它并没有被冻结,因为光标仍在闪烁。我不确定这是为什么。

我已经尝试过对几乎所有我能想到的线程进行线程处理,但我遇到了错误。我已经尝试将加载本地化到 GUI window 本身,但它仍然挂起控制台。这几天在网上找了各种东西都找不到解决办法,所以才转过来!

我的程序有很多 classes 和其他东西,所以我不得不把所有这些东西放在一起,仔细检查,所以如果我遗漏了什么或犯了一个愚蠢的错误,请让我知道,我可以解决它。由于我对 C# 还是有点陌生​​(但对编程并不陌生),我可能也遗漏了问题详细信息中的一些内容。

我想知道解决方案是否是全部基于 GUI,而不是混合控制台和 GUI?根据我在网上找到的信息,两种类型的线程之间似乎存在一些烦人的...差异...?

无论如何,任何帮助都会很棒,过去 3 天我一直在尝试调试它,但没有取得任何进展。如果有帮助,回购 here 有一个 link!谢谢:)

编辑:我在等待响应时做了一些更改,主要是更改它绘制到 GUI 的方式。最初我让它在背景上绘画,但现在让它通过 MediaElement 进行处理。这是我现在 window 的全部 class:

public partial class MainWindow : Window
    {

        public MainWindow(string dir)
        {
            InitializeComponent();

            video.Source = new Uri(dir); //video is the name of my MediaElement
        }

        public void pause(){
            video.Pause();
        }

        public void resume()
        {
            video.Play();
        }

        public void stop()
        {
            video.Stop();
            this.Close();
        }

        public void volume(int i)
        {
            video.Volume = i;
        }
    }

这并没有解决控制台挂起的问题,但是这使一切都更加集中,从而使调试更加容易。希望这可能有所帮助!

考虑将其转换为 WPF 应用程序,这会使事情变得更容易。

无论如何,您仍然可以在不锁定控制台的情况下使用 GUI,但您必须在单独的专用 STA 线程上执行与 GUI 相关的内容。由于您使用的是 WPF,因此此助手应该很有用(此代码不是生产质量的,但可以工作):

static class UIThread
{
    private static Dispatcher _dispatcher;

    public static void Start()
    {
        using(var wh = new ManualResetEvent(false))
        {
            var thread = new Thread(ThreadProc)
            {
                IsBackground = true,
            };
            thread.SetApartmentState(ApartmentState.STA);
            thread.Start(wh);
            wh.WaitOne();
        }
    }

    private static void ThreadProc(object arg)
    {
        var wh = (EventWaitHandle)arg;
        _dispatcher = Dispatcher.CurrentDispatcher;
        wh.Set();
        Dispatcher.Run();
    }

    public static Dispatcher Dispatcher
    {
        get { return _dispatcher; }
    }
}

此助手为您提供对 Dispatcher 对象的引用,该对象用于在 UI 线程上执行方法。

与UI 线程的所有通信都应通过Dispatcher.Invoke()Dispatcher.BeginInvoke() 方法完成。请注意,由于我们现在有多个线程,因此必须在 UI 线程上创建 MediaPlayer 个对象。您仍然可以在任何您想要的线程上保留它的引用,但是对 MediaPlayer 对象的任何方法调用都必须经过 Dispatcher.

要更改的内容:

  • 在尝试使用 Dispatcher 之前添加一个 UIThread.Start(); 调用。 Main() 方法的开头是执行此操作的好地方。
  • MediaPlayer 对象应该这样创建:mediaPlayer = UIThread.Dispatcher.Invoke(() => new Media());
  • 任何与 UI 相关的代码都应转到 Dispatcher.Invoke()Dispatcher.BeginInvoke()UIThread.Dispatcher.BeginInvoke(() => playVideo(@"C:\video.avi"));

更新

同时将 new System.Windows.Application().Run(videoPanel); 更改为简单的 videoPanel.Show()Application.Run() 阻塞,直到 window 关闭。