在开始之前,我想为任何......白痴而道歉......在提出这个问题时我可能会表现出来,我是在尝试从Java学习C#后想到的,只是想要跳进去吧!
我正在开发一个旨在通过控制台接收命令的项目,例如"玩蝙蝠侠开始"它将开始播放电影Batman Begins。它还需要音乐等命令。通过这种设置,我的目标是让它受语音控制,所以我并不真正关心使用GUI而不是控制台。当我让程序播放电影时,它会加载一个没有边框,没有内容的GUI窗口,它使用的构造函数是:
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文件复制粘贴到我的项目(因为我和我很抱歉,我很抱歉)。可能这会导致问题。
此代码(大部分)工作正常。当我运行我的程序时,它会加载视频文件,打开窗口,并在播放声音的同时在屏幕上播放视频。然而,当它启动视频时,GUI"挂起"并且不接受任何输入的OR输出,但是当光标仍然闪烁时它不会被冻结。我不确定为什么会这样。
我尝试过几乎可以想到的任何东西,但是我遇到了错误。我已经尝试将加载本地化到GUI窗口本身,但它仍然挂起控制台。过去几天我一直在网上搜索各种各样的东西,无法找到解决办法,所以我转过来了!
我的程序有更多的课程和内容,所以我不得不把所有这些东西放在一起,并仔细检查,所以如果我错过了什么或做了一个愚蠢的请告诉我,我可以解决它。由于我还是C#的新手(但不是编程新手),我可能也错过了我的问题细节。
我想知道解决方案是否基于GUI而不是混合控制台和GUI?由于我在网上找到的信息,看起来两种类型的线程之间可能存在一些恼人的......差异?
无论如何,任何帮助都会很棒,过去3天我一直试图调试这个并且没有取得任何进展。如果有帮助,就会有一个指向回购here的链接!谢谢:))
编辑:我在等待响应时做了一些更改,主要是改变它绘制到GUI的方式。最初我把它绘制到背景中,但现在通过MediaElement进行处理。这是我窗口的全班:
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;
}
}
这并没有修复控制台挂起,但是这使得所有内容更加集中化,从而使调试更容易。希望这可能有所帮助!
答案 0 :(得分:1)
考虑将其转换为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
。
要改变的事情:
UIThread.Start();
之前添加Dispatcher
来电。 Main()
方法的开头是一个很好的地方。MediaPlayer
个对象应该像这样创建:mediaPlayer = UIThread.Dispatcher.Invoke(() => new Media());
Dispatcher.Invoke()
或Dispatcher.BeginInvoke()
:UIThread.Dispatcher.BeginInvoke(() => playVideo(@"C:\video.avi"));
<强>更新强>
同时将new System.Windows.Application().Run(videoPanel);
更改为简单videoPanel.Show()
。 Application.Run()
阻止,直到窗口关闭。