我正在开发一个项目,旨在通过MediaElement通过WPF窗口播放音频和视频文件。这是窗口的xaml:
<Window x:Class="HomeSystem_CSharp.MediaWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MediaWindow" MinHeight="480" MinWidth="720" WindowStyle="None" ResizeMode="NoResize" Visibility="Visible" Cursor="None">
<Grid Background="Black">
<MediaElement LoadedBehavior="Manual" HorizontalAlignment="Stretch" Name="video" VerticalAlignment="Stretch" Cursor="None" MinHeight="480" MinWidth="720"/>
</Grid>
</Window>
这会创建一个没有边框的窗口,我计划将来进行全面筛选。但就目前而言,我希望桌面上有更多空间。这是我控制MediaElement的代码:
private bool playing = false;
public MediaWindow(string dir)
{
InitializeComponent();
video.Source = new Uri(dir);
play();
}
public void play()
{
if (playing)
return;
if (!this.IsVisible)
this.Show();
video.Play();
playing = true;
}
这个MediaWindow是在对象之外创建的,只需要一个简单的MediaWindow mw = new MediaWindow("C:\\test.mp4");
无论我如何在我的代码中移动内容,启动时每次GUI都没有响应,但声音播放。我可以在后台听到视频,但屏幕上有一个破窗口。只是一个黑盒子。
最大的问题是,就在前几天工作正常,突然间它破了,我不知道发生了什么。我是c#的新手,所以我不知道发生了什么事,但我已经使用java几年了,所以我不是全新的。谁能指出我做错了什么?我可以提供任何其他细节,但我认为我有一切必要的答案。感谢您的帮助,这一直困扰着我,没有任何修复!
编辑:结果,如果我使用
public void play()
{
if (playing)
return;
//if (!this.IsVisible)
// this.Show();
video.Play();
new Application().Run(this);
playing = true;
}
相反,它将运行GUI。但是,这会挂起控制台。最初我通过使用this.Show()修复了挂起,但现在这不起作用。我知道将整个项目转移到WPF项目会解决这个问题,但是我真的不想出于其他原因。现在只有win32。任何想法为什么会发生这种情况以及如何解决它?我的主要功能[STAThread]
如果有所作为。{/ p>
编辑2:
我正在播放的这个视频文件是电影长度,并且可以在任何其他软件中完美运行,以防止出现问题。至于MediaWindow的创作。我做的是创建一个win32控制台项目并在那里设置用户命令。然后我创建了一个新的WPF项目,并创建了一个xaml gui窗口。我拿了那些代码文件,然后将它们复制到win32项目中,并调用它以MediaWindow mw = new MediaWindow("C:\\test.mp4");
的方式在main方法中启动我是这样做的,因为现在我试图远离使用纯WPF应用程序,因为我对C#不熟悉所以我不确定如何在没有复制粘贴方法的情况下创建我想要的窗口。
答案 0 :(得分:1)
好吧,整个混合控制台/图形用户界面对我来说是一个新的事情,但我只是假设真的需要这样做。
Application.Run 方法在应用程序关闭之前不会返回。这就是你的控制台被锁定的原因。
不要在窗口内创建Application对象。在外部做。此外,产生另一个线程以启动视频播放。这将使您的控制台响应。
我不会在描述线程和代表等方面做出重大责任......如果你愿意,你可以查看它。我要回顾一下这个具体例子你需要做些什么。在类的某个位置启动视频但不在方法中,定义一个委托类型,如下所示:
delegate void LaunchVideo(String s);
委托本质上是指向具有特定返回值和参数定义的函数的指针。在这里,我们将委托类型定义为一个接受String参数并且不返回任何内容的函数。接下来,在您要播放视频的代码中,执行以下操作:
LaunchVideo lv = new delegate(String vidfile)
{
Application app = new Application();
app.Run(new MediaWindow(vidfile));
};
IAsyncResult result = lv.BeginInvoke( "C:\\vid.mp4", myVideoCompleted, null );
这将创建委托变量并将其指向匿名函数,该函数可创建应用程序并启动视频播放。然后它调用委托的 BeginInvoke 方法,该方法是基本委托类的一部分。这会生成一个在委托所指向的函数中运行的新线程。
请注意,使用此类窗口参数调用 Application.Run 会打开窗口但不会调用 play()方法。您可能希望将该代码移动到构造函数中,或者在构造函数中添加对它的调用。
请注意,除非使用 lock 函数使线程安全,否则主线程无法安全地调用在调用的线程中创建的对象中的方法。
如果您需要&#34;打开&#34;和&#34;玩&#34;要是由控制台调用的单独控制的事件,那么你必须找出一种方法将消息从控制台线程传递给窗口线程。
BeginInvoke的参数列表始终以您要调用的函数所期望的任何参数开始。所以在这种情况下,这是带有视频文件名的字符串。 Next是调用函数退出时将调用的回调函数的名称。它是一个带有 AsyncResult 参数的void函数,如下所示:
void myVideoCompleted(AsyncResult result)
{
// Do whatever here... Be aware this is still on the other thread
}
您可以使用&#39; null&#39;如果你不需要在最后调用任何东西,而不是函数名。请注意,如果您使用回调函数,它将在BeginInvoke启动的新线程上运行,而不是在调用它的线程上运行。
BeginInvoke的最后一个参数是一个对象,它将通过AsyncResult参数的 AsyncState 成员传递给回调函数。你可以通过&#39; null&#39;如果你没有使用回调,或者你没有回调所需的参数。
您还可以调用委托的 EndInvoke 方法来取回该函数可能返回的任何结果。但是,请注意,如果调用的函数尚未完成,则会阻止此操作。在这种情况下,您无需担心结果。
答案 1 :(得分:1)
无论我如何在我的代码中移动内容,每次启动时GUI都没有响应,但声音播放。
我设法重现了这一点。您的描述中缺少的一个重要事项是您在main()方法中创建和显示窗口的确切方式。例如,以下内容会冻结录制声音的视频:
[STAThread]
static void Main(string[] args)
{
var w = new MediaWindow();
w.Show();
Console.ReadLine();
}
下一个“冻结”控制台,直到你关闭窗口:
[STAThread]
static void Main(string[] args)
{
var w = new MediaWindow();
w.ShowDialog();
Console.ReadLine();
}
这使你们两个都工作:
static void Main(string[] args)
{
var thread = new Thread(ShowMediaWindow);
thread.SetApartmentState(ApartmentState.STA);
thread.Start();
while (true) // Just to test console working
{
Console.Write("\r" + DateTime.Now);
Thread.Sleep(100);
}
}
static void ShowMediaWindow()
{
new MediaWindow().ShowDialog();
}
如您所见,控制台和WPF窗口无法在单个线程中正常工作。
顺便说一句,窗口类就像这样简单(XAML与你的大致相同):
public partial class MediaWindow : Window
{
public MediaWindow()
{
InitializeComponent();
video.Source = new Uri(@"C:\video\test.asf");
Play();
}
public void Play()
{
video.Play();
}
}
我想这样做可以从控制台显示视频播放器窗口。