我有一个正在使用的应用程序,我希望一个窗口成为控制器,另一个窗口成为视频播放器视图。
这样做的目的是控制在投影机上播放视频时可以从笔记本电脑上观看的一个窗口中播放视频。最终,我想对其进行设置,以便可以拥有一组16个视频,我可以使用键盘触发这些视频以在视频播放器视图中播放,当我按下与特定视频相关联的键(通过选择器选择)时,停止当前正在播放的视频)并开始播放新视频。
请注意,如果有更好的语言和/或系统来创建此Windows应用程序,除了我要询问的内容之外,我欢迎其他建议。
这是我的MainPage.xaml.cs:
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices.WindowsRuntime;
using Windows.ApplicationModel.Core;
using Windows.Foundation;
using Windows.Foundation.Collections;
using Windows.UI.Core;
using Windows.UI.ViewManagement;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Controls.Primitives;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Navigation;
namespace VideoSamplePlayer
{
public sealed partial class MainPage : Page
{
int newViewID = 0;
Window VideoPlayerWindow;
public MainPage()
{
this.InitializeComponent();
}
private async void Button_Click(object sender, RoutedEventArgs e)
{
if (newViewID == 0) {
var myView = CoreApplication.CreateNewView();
await myView.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
{
Frame newFrame = new Frame();
newFrame.Navigate(typeof(VideoPlayer), null);
Window.Current.Content = newFrame;
Window.Current.Activate();
VideoPlayerWindow = Window.Current;
newViewID = ApplicationView.GetForCurrentView().Id;
});
await ApplicationViewSwitcher.TryShowAsStandaloneAsync(newViewID, ViewSizePreference.UseMinimum);
}
}
}
}
这是我的MainPage.xaml:
<Page
x:Class="VideoSamplePlayer.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:VideoSamplePlayer"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Grid>
<Button Content="Open Video Output" HorizontalAlignment="Center" Margin="0,55,0,0" VerticalAlignment="Top" Height="52" Width="173" Click="Button_Click"/>
</Grid>
</Page>
这是我的VideoPlayer.xaml.cs:
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices.WindowsRuntime;
using Windows.Foundation;
using Windows.Foundation.Collections;
using Windows.Media.Core;
using Windows.Storage;
using Windows.Storage.Pickers;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Controls.Primitives;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Navigation;
namespace VideoSamplePlayer
{
public sealed partial class VideoPlayer : Page
{
public VideoPlayer()
{
this.InitializeComponent();
}
private async void pickFileButton_Click(object sender, RoutedEventArgs e)
{
// Create and open the file picker
FileOpenPicker openPicker = new FileOpenPicker();
openPicker.ViewMode = PickerViewMode.Thumbnail;
openPicker.SuggestedStartLocation = PickerLocationId.VideosLibrary;
openPicker.FileTypeFilter.Add(".mp4");
openPicker.FileTypeFilter.Add(".mkv");
openPicker.FileTypeFilter.Add(".avi");
StorageFile file = await openPicker.PickSingleFileAsync();
if (file != null)
{
mediaPlayerElement.MediaPlayer.Source = MediaSource.CreateFromStorageFile(file);
mediaPlayerElement.MediaPlayer.RealTimePlayback = true;
mediaPlayerElement.MediaPlayer.Play();
}
}
}
}
这是我的VideoPlayer.xaml:
<Page
x:Class="VideoSamplePlayer.VideoPlayer"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:VideoSamplePlayer"
xmlns:mediacore="using:Windows.Media.Core"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Grid>
<StackPanel Orientation = "Vertical" >
<StackPanel Orientation="Horizontal">
<Button x:Name="pickFileButton" Content="Pick video" Margin="0,0,0,10" Click="pickFileButton_Click"/>
</StackPanel>
<MediaPlayerElement x:Name="mediaPlayerElement"
AutoPlay="False" Margin="5"
HorizontalAlignment="Stretch"
Height="300"
AreTransportControlsEnabled="True"/>
</StackPanel>
</Grid>
</Page>
我想将文件选择器按钮移到MainPage,但是VideoPlayer中仍然有视频输出。
我怎样才能做到这一点?
谢谢!
进行了一些尝试,但终于找到了解决方案!诀窍是使用自定义事件...而棘手的部分是我们正在使用多个线程(每个窗口都在其自己的线程中运行)。
基本上,我们将按钮及其处理程序移至MainPage,但在VideoPlayer
页面上保留与视频播放器交互的行。然后,我们需要声明一个自定义事件,该事件允许MainPage告知VideoPlayer
已选择了视频,并将选定的视频传递给VideoPlayer
页面。最后,该VideoPlayer
页面可以为MediaPlayerElement
它包含的实际内容设置源和详细信息,并实际播放视频。
让我们看一下每个部分:
首先在上声明您的自定义事件MainPage
:
public delegate void VideoSelectedHandler(object sender, VideoSelectionArgs e);
public event VideoSelectedHandler VideoSelected;
private void RaiseVideoSelectedEvent(MediaSource source)
{
// Ensure that something is listening to the event.
if (this.VideoSelected != null)
{
// Create the args, and call the listening event handlers.
VideoSelectionArgs args = new VideoSelectionArgs(source);
this.VideoSelected(this, args);
}
}
您还需要为事件参数声明类(适当地,它继承自EventArgs
。您可以在同一文件(但在MainPage
类外部)或其他文件中声明它:
public class VideoSelectionArgs : EventArgs
{
public MediaSource Source { get; private set; }
public VideoSelectionArgs(MediaSource source)
{
this.Source = source;
}
}
接下来,我们需要VideoPlayer
页面来订阅事件,以便它侦听正在引发的事件。将事件处理程序添加到VideoPlayer
页面:
public void VideoSelected(object sender, VideoSelectionArgs e)
{
mediaPlayerElement.MediaPlayer.Source = e.Source;
mediaPlayerElement.MediaPlayer.RealTimePlayback = true;
mediaPlayerElement.MediaPlayer.Play();
}
请注意,这是负责设置的代码MediaPlayerElement
,并接受MediaSource
来自事件的参数。
接下来,该VideoPlayer
页面订阅MainPage
的活动。在您的Button_Click
事件处理程序中MainPage
,我们需要添加两行:
Frame newFrame = new Frame();
newFrame.Navigate(typeof(VideoPlayer), null);
// These are the two new lines... the others are shown for reference of where to place these.
VideoPlayer videoPlayerPage = newFrame.Content as VideoPlayer;
this.VideoSelected += videoPlayerPage.VideoSelected;
Window.Current.Content = newFrame;
Window.Current.Activate();
VideoPlayerWindow = Window.Current;
现在,您可以简单地从pickFileButton_Click
处理程序中调用此事件(现在在上MainPage
,然后传入MediaSource
从FileOpenPicker
...中获得的事件,但这是您可能会遇到麻烦的地方(这是我花了最长时间找出的)。
我们必须记住,每个窗口都在自己的线程上运行。即使您从另一个窗口调用代码,该代码仍在从其调用的线程上运行。这意味着,如果您仅执行上述操作,代码将编译并运行,但是当您尝试选择视频文件时,会出现运行时错误,并显示一条消息,指出资源已编组在另一个线程上。
解决方案是安排在与第二个窗口运行时相同的线程上获取视频文件的工作。因此,我们需要再进行两次修改才能完成此操作。
首先,我们有一个概念Dispatcher
。每个控件都有一个。您已经使用了Dispatcher
与新视图(使用声明的)相关联var myView
。Dispatcher
需要使用相同的视图来安排视频文件的工作,因此我们需要维护对它的引用。只需将属性添加到您的MainPage
:
CoreApplicationView VideoPlayerView { get; set; }
并调整视图创建,以创建该属性的新视图,而不是var myView
:
VideoPlayerView = CoreApplication.CreateNewView();
await VideoPlayerView.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
…
最后,我们可以设置pickFileButton_Click
处理程序。将您的按钮(按钮本身的XAML中无需修改)移至MainPage.xaml
。然后,将点击处理程序也移到MainPage,但进行以下两个修改:
mediaPlayerElement
(现在在VideoPlayer
页面上的自定义事件处理程序中)的代码。致电以引发自定义事件。现在位于上的经过修改的事件处理程序MainPage
如下所示:
private async void pickFileButton_Click(object sender, RoutedEventArgs e)
{
// Schedule the work here on the same thread as the VideoPlayer window,
// so that it has access to the file and MediaSource to play.
await this.VideoPlayerView.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, async () =>
{
// Create and open the file picker
FileOpenPicker openPicker = new FileOpenPicker();
openPicker.ViewMode = PickerViewMode.Thumbnail;
openPicker.SuggestedStartLocation = PickerLocationId.VideosLibrary;
openPicker.FileTypeFilter.Add(".mp4");
openPicker.FileTypeFilter.Add(".mkv");
openPicker.FileTypeFilter.Add(".avi");
StorageFile file = await openPicker.PickSingleFileAsync();
if (file != null)
{
MediaSource sourceFromFile = MediaSource.CreateFromStorageFile(file);
// Raise the event declaring that a video was selected.
this.RaiseVideoSelectedEvent(sourceFromFile);
}
});
}
那应该做到的!我确实测试了代码,并使其成功在计算机上与真实视频文件一起运行。
希望有帮助!
完整代码的最终形式如下:
MainPage.xaml.cs
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices.WindowsRuntime;
using Windows.ApplicationModel.Core;
using Windows.Foundation;
using Windows.Foundation.Collections;
using Windows.UI.Core;
using Windows.UI.ViewManagement;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Controls.Primitives;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Navigation;
namespace VideoSamplePlayer
{
public sealed partial class MainPage : Page
{
int newViewID = 0;
Window VideoPlayerWindow;
// To store the reference to the view control, so that it's dispatcher
// can be used to schedule more work on its thread.
CoreApplicationView VideoPlayerView { get; set; }
// The custom event declaration, to be raised when a media source for the video
// is selected.
public delegate void VideoSelectedHandler(object sender, VideoSelectionArgs e);
public event VideoSelectedHandler VideoSelected;
private void RaiseVideoSelectedEvent(MediaSource source)
{
// Ensure that something is listening to the event.
if (this.VideoSelected != null)
{
// Create the args, and call the listening event handlers.
VideoSelectionArgs args = new VideoSelectionArgs(source);
this.VideoSelected(this, args);
}
}
public MainPage()
{
this.InitializeComponent();
}
private async void Button_Click(object sender, RoutedEventArgs e)
{
if (newViewID == 0)
{
// Store the newly created view control.
this.VideoPlayerView = CoreApplication.CreateNewView();
await this.VideoPlayerView.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
{
Frame newFrame = new Frame();
newFrame.Navigate(typeof(VideoPlayer), null);
// Have the new VideoPlayer page subscribe to the media source selection event on this page.
VideoPlayer videoPlayerPage = newFrame.Content as VideoPlayer;
this.VideoSelected += videoPlayerPage.VideoSelected;
Window.Current.Content = newFrame;
Window.Current.Activate();
VideoPlayerWindow = Window.Current;
newViewID = ApplicationView.GetForCurrentView().Id;
});
await ApplicationViewSwitcher.TryShowAsStandaloneAsync(newViewID, ViewSizePreference.UseMinimum);
}
}
private async void pickFileButton_Click(object sender, RoutedEventArgs e)
{
// Schedule the work here on the same thread as the VideoPlayer window,
// so that it has access to the file and MediaSource to play.
await this.VideoPlayerView.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, async () =>
{
// Create and open the file picker
FileOpenPicker openPicker = new FileOpenPicker();
openPicker.ViewMode = PickerViewMode.Thumbnail;
openPicker.SuggestedStartLocation = PickerLocationId.VideosLibrary;
openPicker.FileTypeFilter.Add(".mp4");
openPicker.FileTypeFilter.Add(".mkv");
openPicker.FileTypeFilter.Add(".avi");
StorageFile file = await openPicker.PickSingleFileAsync();
if (file != null)
{
MediaSource sourceFromFile = MediaSource.CreateFromStorageFile(file);
// Raise the event declaring that a video was selected.
this.RaiseVideoSelectedEvent(sourceFromFile);
}
});
}
}
// Class definition for the custom event args, which allows a
// media source to be passed to any event handlers that are listening.
public class VideoSelectionArgs : EventArgs
{
public MediaSource Source { get; private set; }
public VideoSelectionArgs(MediaSource source)
{
this.Source = source;
}
}
}
VideoPlayer.xaml.cs
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices.WindowsRuntime;
using Windows.Foundation;
using Windows.Foundation.Collections;
using Windows.Media.Core;
using Windows.Storage;
using Windows.Storage.Pickers;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Controls.Primitives;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Navigation;
namespace VideoSamplePlayer
{
public sealed partial class VideoPlayer : Page
{
public VideoPlayer()
{
this.InitializeComponent();
}
// The event handler, which will listen for MainPage's VideoSelected
// event, after being subscribed to it on the MainPage.
public void VideoSelected(object sender, VideoSelectionArgs e)
{
// Get the MediaSource from the event arguments, and set up and start
// the media player.
mediaPlayerElement.MediaPlayer.Source = e.Source;
mediaPlayerElement.MediaPlayer.RealTimePlayback = true;
mediaPlayerElement.MediaPlayer.Play();
}
}
}
注意:此代码已通过在打开第二个窗口后单击“选择视频”按钮进行了测试。您可能需要做更多的工作,以确保在打开第二个窗口之前可以安全单击(或简单地将其隐藏,直到打开第二个窗口)。
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句