在 UWP 中完全关闭辅助视图
Close secondary view completely in UWP
我正在使用 运行 我的媒体文件的辅助视图,但是当我使用关闭按钮关闭辅助视图时(媒体仍在播放时)辅助 view/window 关闭但媒体以某种方式继续播放,因为我可以听到声音并且声音来源似乎是主要视图(主应用程序 window)。如何在关闭时完全终止辅助 window?
这是我创建辅助视图的代码。
await CoreApplication.CreateNewView().Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
{
var frame = new Frame();
frame.MinHeight = 200;
frame.MinWidth = 200;
compactViewId = ApplicationView.GetForCurrentView().Id;
frame.Navigate(typeof(CompactNowPlayingPage), caption);
Window.Current.Content = frame;
Window.Current.Activate();
ApplicationView.GetForCurrentView().Title = Title;
});
bool viewShown = await ApplicationViewSwitcher.TryShowAsViewModeAsync(compactViewId, ApplicationViewMode.Default);
更新
经过一些调试后,我知道在辅助视图上按下关闭按钮只会隐藏视图,但它会在其线程上保持 运行ning,我只希望关闭按钮完全关闭辅助视图,关闭它的线程并销毁整个 window。
更新 2
我按照 windows 对多个视图进行了采样并能够完成所有步骤,代码 运行 没问题,直到它在发布的事件中达到 Windows.Current.Close()
。
然后当它尝试 "Window.Current.Close()" 时它会在发布的事件中给出一个异常。根据文档,由于任何正在进行的更改(可能是因为正在播放媒体文件)会发生异常,但是即使正在播放媒体文件,我也需要强制关闭 window 我该怎么做?这是例外情况:
Message = "COM object that has been separated from its underlying RCW cannot be used."
更新 3
这是最新的更新,我现在不是按照官方示例,只是按照更简单的方法。
打开辅助视图的代码:
await Helpers.DeviceTypeHelper.CompactOpen(e.ClickedItem as Video, identifier); //where identified is just a string for some custom logic in the secondary view.
//following method is located in a helper class within the project
internal static async Task CompactOpen(Video PlayingVideo, string caption)
{
ApplicationView newView = null;
await CoreApplication.CreateNewView().Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
{
var frame = new Frame();
frame.Navigate(typeof(CompactNowPlayingPage),new object[] { PlayingVideo,caption});
Window.Current.Content = frame;
Window.Current.Activate();
newView = ApplicationView.GetForCurrentView();
newView.Title = PlayingVideo.MyVideoFile.DisplayName;
});
await ApplicationViewSwitcher.TryShowAsStandaloneAsync(newView.Id);
}
二级视图:
public sealed partial class CompactNowPlayingPage : Page
{
public CompactNowPlayingViewModel ViewModel { get; } = new CompactNowPlayingViewModel();
private CustomMediaTransportControls controls;
public CompactNowPlayingPage()
{
InitializeComponent();
this.Loaded += MediaPage_Loaded;
this.Unloaded += MediaPage_Unloaded;
Microsoft.Toolkit.Uwp.UI.Extensions.ApplicationView.SetExtendViewIntoTitleBar(this, true);
Microsoft.Toolkit.Uwp.UI.Extensions.TitleBar.SetButtonBackgroundColor(this, Colors.Transparent);
}
protected override void OnNavigatedTo(NavigationEventArgs e)
{
string chk = "";
var paramm = e.Parameter as object[];
NowPlayingVideo = paramm[0] as Video;
var vis = Visibility.Collapsed;
chk = paramm[1].ToString();
switch (chk)
{
case "library":
vis = Visibility.Visible;
break;
case "playlist":
vis = Visibility.Visible;
break;
case "history":
vis = Visibility.Collapsed;
break;
case "directplay":
vis = Visibility.Collapsed;
break;
default:
break;
}
controls = new CustomMediaTransportControls(NowPlayingVideo,vis);
Media.TransportControls = controls;
PlayVideo();
}
private Video NowPlayingVideo { get; set; }
private void PlayVideo()
{
if (NowPlayingVideo != null)
{
string token = "";
if (StorageApplicationPermissions.FutureAccessList.Entries.Count == 800)
{
var en = StorageApplicationPermissions.FutureAccessList.Entries;
StorageApplicationPermissions.FutureAccessList.Remove(en.Last().Token);
}
token = StorageApplicationPermissions.FutureAccessList.Add(NowPlayingVideo.MyVideoFile);
Media.Source = null;
Media.Source = $"winrt://{token}";
SetViews();
}
}
private void SetViews()
{
NowPlayingVideo.Views++;
Database.DbHelper.UpdateViews(NowPlayingVideo.MyVideoFile.Path);
}
private void MediaPage_Loaded(object sender, RoutedEventArgs e)
{
Windows.UI.ViewManagement.ApplicationView.GetForCurrentView().Consolidated += MediaPage_Consolidated;
}
private void MediaPage_Unloaded(object sender, RoutedEventArgs e)
{
Windows.UI.ViewManagement.ApplicationView.GetForCurrentView().Consolidated -= MediaPage_Consolidated;
}
private void MediaPage_Consolidated(Windows.UI.ViewManagement.ApplicationView sender, Windows.UI.ViewManagement.ApplicationViewConsolidatedEventArgs args)
{
Window.Current.Close();
}
}
二级视图XAML:
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<vlc:MediaElement AreTransportControlsEnabled="True"
Name="Media"
HardwareAcceleration="True"
AutoPlay="True">
</vlc:MediaElement>
</Grid>
案例 1: 如果我将视频文件放在 Assets 文件夹中并将其作为媒体元素的来源并评论整个 运行 一切都完美 OnanvigatdTo 辅助页面上的方法。而且我也能够成功关闭 window。
...
案例 2: 但是当我尝试通过 NowPlayingVideo 对象设置媒体时,如上面的代码所示,我也使用默认传输控制,所以我没有在上面的代码中注释用于分配自定义传输控制的行 运行 没问题,但是当我尝试关闭 window 时,我在 App.i.g.cs 文件但堆栈跟踪不存在:
Message = "Attempt has been made to use a COM object that does not have a backing class factory." Message = "无法使用与其底层 RCW 分离的 COM 对象。
案例 3: 与案例 2 完全一样,但在这里我取消了自定义传输控制线的注释,所以现在我将自定义传输控制分配给我的媒体元素,这次例外有点不同还有一些堆栈跟踪
StackTrace = " at System.StubHelpers.StubHelpers.GetCOMIPFromRCW_WinRT(Object objSrc, IntPtr pCPCMD, IntPtr& ppTarget)\r\n at Windows.UI.Xaml.DependencyObject.get_Dispatcher()\r\n at VLC.MediaElement.d__160.MoveNext()\r\n---堆栈跟踪结束...
留言="Attempt has been made to use a COM object that does not have a backing class factory."
简短的回答是:您需要确保没有任何内容保留在您的视图实例中,并且您在视图的 Consolidated 事件中调用 Window.Close。更长的代码答案在官方示例中。查看 ViewLifetimeControl.cs 源文件:https://github.com/Microsoft/Windows-universal-samples/tree/master/Samples/MultipleViews/cs
我正在使用 运行 我的媒体文件的辅助视图,但是当我使用关闭按钮关闭辅助视图时(媒体仍在播放时)辅助 view/window 关闭但媒体以某种方式继续播放,因为我可以听到声音并且声音来源似乎是主要视图(主应用程序 window)。如何在关闭时完全终止辅助 window?
这是我创建辅助视图的代码。
await CoreApplication.CreateNewView().Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
{
var frame = new Frame();
frame.MinHeight = 200;
frame.MinWidth = 200;
compactViewId = ApplicationView.GetForCurrentView().Id;
frame.Navigate(typeof(CompactNowPlayingPage), caption);
Window.Current.Content = frame;
Window.Current.Activate();
ApplicationView.GetForCurrentView().Title = Title;
});
bool viewShown = await ApplicationViewSwitcher.TryShowAsViewModeAsync(compactViewId, ApplicationViewMode.Default);
更新
经过一些调试后,我知道在辅助视图上按下关闭按钮只会隐藏视图,但它会在其线程上保持 运行ning,我只希望关闭按钮完全关闭辅助视图,关闭它的线程并销毁整个 window。
更新 2
我按照 windows 对多个视图进行了采样并能够完成所有步骤,代码 运行 没问题,直到它在发布的事件中达到 Windows.Current.Close()
。
然后当它尝试 "Window.Current.Close()" 时它会在发布的事件中给出一个异常。根据文档,由于任何正在进行的更改(可能是因为正在播放媒体文件)会发生异常,但是即使正在播放媒体文件,我也需要强制关闭 window 我该怎么做?这是例外情况:
Message = "COM object that has been separated from its underlying RCW cannot be used."
更新 3
这是最新的更新,我现在不是按照官方示例,只是按照更简单的方法。
打开辅助视图的代码:
await Helpers.DeviceTypeHelper.CompactOpen(e.ClickedItem as Video, identifier); //where identified is just a string for some custom logic in the secondary view.
//following method is located in a helper class within the project
internal static async Task CompactOpen(Video PlayingVideo, string caption)
{
ApplicationView newView = null;
await CoreApplication.CreateNewView().Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
{
var frame = new Frame();
frame.Navigate(typeof(CompactNowPlayingPage),new object[] { PlayingVideo,caption});
Window.Current.Content = frame;
Window.Current.Activate();
newView = ApplicationView.GetForCurrentView();
newView.Title = PlayingVideo.MyVideoFile.DisplayName;
});
await ApplicationViewSwitcher.TryShowAsStandaloneAsync(newView.Id);
}
二级视图:
public sealed partial class CompactNowPlayingPage : Page
{
public CompactNowPlayingViewModel ViewModel { get; } = new CompactNowPlayingViewModel();
private CustomMediaTransportControls controls;
public CompactNowPlayingPage()
{
InitializeComponent();
this.Loaded += MediaPage_Loaded;
this.Unloaded += MediaPage_Unloaded;
Microsoft.Toolkit.Uwp.UI.Extensions.ApplicationView.SetExtendViewIntoTitleBar(this, true);
Microsoft.Toolkit.Uwp.UI.Extensions.TitleBar.SetButtonBackgroundColor(this, Colors.Transparent);
}
protected override void OnNavigatedTo(NavigationEventArgs e)
{
string chk = "";
var paramm = e.Parameter as object[];
NowPlayingVideo = paramm[0] as Video;
var vis = Visibility.Collapsed;
chk = paramm[1].ToString();
switch (chk)
{
case "library":
vis = Visibility.Visible;
break;
case "playlist":
vis = Visibility.Visible;
break;
case "history":
vis = Visibility.Collapsed;
break;
case "directplay":
vis = Visibility.Collapsed;
break;
default:
break;
}
controls = new CustomMediaTransportControls(NowPlayingVideo,vis);
Media.TransportControls = controls;
PlayVideo();
}
private Video NowPlayingVideo { get; set; }
private void PlayVideo()
{
if (NowPlayingVideo != null)
{
string token = "";
if (StorageApplicationPermissions.FutureAccessList.Entries.Count == 800)
{
var en = StorageApplicationPermissions.FutureAccessList.Entries;
StorageApplicationPermissions.FutureAccessList.Remove(en.Last().Token);
}
token = StorageApplicationPermissions.FutureAccessList.Add(NowPlayingVideo.MyVideoFile);
Media.Source = null;
Media.Source = $"winrt://{token}";
SetViews();
}
}
private void SetViews()
{
NowPlayingVideo.Views++;
Database.DbHelper.UpdateViews(NowPlayingVideo.MyVideoFile.Path);
}
private void MediaPage_Loaded(object sender, RoutedEventArgs e)
{
Windows.UI.ViewManagement.ApplicationView.GetForCurrentView().Consolidated += MediaPage_Consolidated;
}
private void MediaPage_Unloaded(object sender, RoutedEventArgs e)
{
Windows.UI.ViewManagement.ApplicationView.GetForCurrentView().Consolidated -= MediaPage_Consolidated;
}
private void MediaPage_Consolidated(Windows.UI.ViewManagement.ApplicationView sender, Windows.UI.ViewManagement.ApplicationViewConsolidatedEventArgs args)
{
Window.Current.Close();
}
}
二级视图XAML:
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<vlc:MediaElement AreTransportControlsEnabled="True"
Name="Media"
HardwareAcceleration="True"
AutoPlay="True">
</vlc:MediaElement>
</Grid>
案例 1: 如果我将视频文件放在 Assets 文件夹中并将其作为媒体元素的来源并评论整个 运行 一切都完美 OnanvigatdTo 辅助页面上的方法。而且我也能够成功关闭 window。 ...
案例 2: 但是当我尝试通过 NowPlayingVideo 对象设置媒体时,如上面的代码所示,我也使用默认传输控制,所以我没有在上面的代码中注释用于分配自定义传输控制的行 运行 没问题,但是当我尝试关闭 window 时,我在 App.i.g.cs 文件但堆栈跟踪不存在:
Message = "Attempt has been made to use a COM object that does not have a backing class factory." Message = "无法使用与其底层 RCW 分离的 COM 对象。
案例 3: 与案例 2 完全一样,但在这里我取消了自定义传输控制线的注释,所以现在我将自定义传输控制分配给我的媒体元素,这次例外有点不同还有一些堆栈跟踪
StackTrace = " at System.StubHelpers.StubHelpers.GetCOMIPFromRCW_WinRT(Object objSrc, IntPtr pCPCMD, IntPtr& ppTarget)\r\n at Windows.UI.Xaml.DependencyObject.get_Dispatcher()\r\n at VLC.MediaElement.d__160.MoveNext()\r\n---堆栈跟踪结束...
留言="Attempt has been made to use a COM object that does not have a backing class factory."
简短的回答是:您需要确保没有任何内容保留在您的视图实例中,并且您在视图的 Consolidated 事件中调用 Window.Close。更长的代码答案在官方示例中。查看 ViewLifetimeControl.cs 源文件:https://github.com/Microsoft/Windows-universal-samples/tree/master/Samples/MultipleViews/cs