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 关闭。
在我开始之前,我想为我在问这个问题时可能表现出的任何...白痴道歉,我正在尝试学习 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 关闭。