在第二个窗口中显示视频(UWP C#)

用户名

我有一个正在使用的应用程序,我希望一个窗口成为控制器,另一个窗口成为视频播放器视图。

这样做的目的是控制在投影机上播放视频时可以从笔记本电脑上观看的一个窗口中播放视频。最终,我想对其进行设置,以便可以拥有一组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,然后传入MediaSourceFileOpenPicker...中获得的事件,但这是您可能会遇到麻烦的地方(这是我花了最长时间找出的)。

我们必须记住,每个窗口都在自己的线程上运行。即使您从另一个窗口调用代码,该代码仍在从其调用的线程上运行。这意味着,如果您仅执行上述操作,代码将编译并运行,但是当您尝试选择视频文件时,会出现运行时错误,并显示一条消息,指出资源已编组在另一个线程上。

解决方案是安排在与第二个窗口运行时相同的线程上获取视频文件的工作因此,我们需要再进行两次修改才能完成此操作。

首先,我们有一个概念Dispatcher每个控件都有一个。您已经使用了Dispatcher与新视图(使用声明的)相关联var myViewDispatcher需要使用相同的视图来安排视频文件的工作,因此我们需要维护对它的引用。只需将属性添加到您的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] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

如何显示当前和更新的(到第二个)DateTime.Now C#

C#-弹出窗口未显示在MVVM的第二个选项卡项中

C#检查第二个屏幕的方向

C#方法第二个参数可选

C#双屏应用程序,如何从第二个窗口更改主窗口的框架?

如何创建一个计时器来显示第二个C#的图像

C#UWP为什么我不能添加第二个事件处理程序?

在C#中用逗号分隔符显示文本中第二个最长的单词

C# 表单应用程序(如何显示();第二个表单首先使用按钮

C ++窗口应用程序随附加窗口一起打开。如何摆脱第二个窗口?

C#-Console.WriteLine()不显示第二个参数

C ++列表屏幕在第二个监视器中显示图像

在 C# 中关闭第一个表单以显示第二个,但在关闭第二个后第一个又回来了

Appium - 通过 xpath c# 查找第二个元素

C#。在第二个字符后用点分隔字符串

C#,XML:将第二个名称空间移至根元素

优化 C# lambda 查询以访问 linq 查询中的第二个相关字段

打开第二个表单C#后拒绝访问com端口

单击第二个按钮上的“参数太多”,C#

C# 在按下第二个键时调用函数

用C#代码打开第二个创建的文件夹

C#从第二个列表中删除元素

在C#中将第二个参数传递给存储过程

C#从txt文件中读取第二个单词

c# 和 sqlserver 如何从第二个表中获取数据(如果存在)

如何中断到第二个 foreachloop c#

特定字符后的第二个值的 C# 排序字符串

解锁第二个屏幕的目标c

无法打开第二个文件C