3

I am using a secondary view to run my media files, but When I close my secondary view with close button on it (while media is still playing) the secondary view/window closes but the media somehow keeps playing because I can hear the sound and source of sound seems to be the primary view (main app window). How can I completely terminate the secondary window when I close it?

Here is my code to create the secondary view.

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);

Update

After some debugging I've come to know that close button pressed on the secondary view only hides the view but it keeps on running on its thread, I just want that close button to completely close the secondary view, close its thread and destroy the window as a whole.

Update 2

I followed windows samples multiple views and was able to complete all steps, the code runs fine until it reaches Windows.Current.Close() in released event.

Then it gives an exception when it tries "Window.Current.Close()" with in the released event. according to documentation exception occurs due to any on going changes ( which might be because of media file playing ), but I need to force close the window even when media file is playing how can I do that? Here is the exception:

Message = "COM object that has been separated from its underlying RCW cannot be used."

Update 3

This is the latest updated, I am not following official sample now, just following simpler approach now.

Code to open secondary view:

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);

}  

Secondary View:

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();
    }

}

Secondary View XAML:

<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
    <vlc:MediaElement AreTransportControlsEnabled="True"
                      Name="Media"                     
                      HardwareAcceleration="True"
                      AutoPlay="True">
    </vlc:MediaElement>
</Grid>

Case 1 : Everything runs perfect if I place a video file in Assets folder and give it as a source to the media element and comment the whole OnanvigatdTo method on secondary page. And I am able to successfully close the window as well. ...

Case 2 : But when I try to set the media through the NowPlayingVideo object as shown in the code above and I also use default Transport Controls, so I don't comment the lines used to assign custom transport controls in the above code it runs fine, but when I then try to close the window I get following exception in App.i.g.cs file but stacktrace doesn't exist:

Message = "Attempt has been made to use a COM object that does not have a backing class factory." Message = "COM object that has been separated from its underlying RCW cannot be used.

Case 3 : Exactly like case 2 but here I uncomment Custom transport controls lines so now I am assigning custom transport controls to my media element, this time exception is a bit different with some stacktrace as well

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--- End of stack trace ...

Message = "Attempt has been made to use a COM object that does not have a backing class factory."

halfer
  • 19,824
  • 17
  • 99
  • 186
Muhammad Touseef
  • 4,357
  • 4
  • 31
  • 75

1 Answers1

3

The short answer is: you need to make sure nothings holds on to your view instance, and you call Window.Close in the view's Consolidated event. The longer answer with code is here in the official sample. Take a look at the ViewLifetimeControl.cs source file: https://github.com/Microsoft/Windows-universal-samples/tree/master/Samples/MultipleViews/cs

Stefan Wick MSFT
  • 13,600
  • 1
  • 32
  • 51
  • the view object doesnt even have a Consolidated event :/ – Muhammad Touseef Jun 07 '17 at 20:46
  • ApplicationView.GetForCurrentView has it but CoreApplicationView doesnt have it – Muhammad Touseef Jun 07 '17 at 20:55
  • Yes, you listen to the Consolidated event on the ApplicationView instance: https://learn.microsoft.com/en-us/uwp/api/Windows.UI.ViewManagement.ApplicationView#events_ – Stefan Wick MSFT Jun 07 '17 at 21:02
  • I tried as u suggested and used the helper class from sample project and launched my secondary view according to Scenario 1 of the sample and then when I close it, consolidated event fires as it should but it gives me error on this specific line ( Line No. 129 in file ViewLifeTimeControl.cs ) InternalReleased(this, null);// null reference exception Apparently Internal Released is null due to some unknown reason – Muhammad Touseef Jun 07 '17 at 22:40
  • The sample assumes that your page subscribes to the Released event on the ViewLifetimeControl, see here: https://github.com/Microsoft/Windows-universal-samples/blob/master/Samples/MultipleViews/cs/SecondaryViewPage.xaml.cs – Stefan Wick MSFT Jun 07 '17 at 23:03
  • I was successfully able to subscribe to Released event and now it proceeds but then it gives an exception when it tries "Window.Current.Close()" with in the released event. according to documentation exception occurs due to any on going changes ( which might be because of media file playing ), but I need to force close the window even when media file is playing how can I do that? btw here is the exception : Message = "COM object that has been separated from its underlying RCW cannot be used." – Muhammad Touseef Jun 08 '17 at 09:33
  • I have put together a concise sample for you, please let me know if this doesn't work for you: https://1drv.ms/u/s!AovTwKUMywTNl5NPfMrn4gEYnG4keg – Stefan Wick MSFT Jun 11 '17 at 18:26
  • @Stefan_Wich_MSFT your sample works just fine when I include it in my project, but there is one problem, I am actually supplying "Video" class object to the "CompactNowPlayingPage.xaml.cs" class (which has a public static Video field for this purpose) before actually creating the secondary window, so when I try to close it gives me following exception : Message = "Attempt has been made to use a COM object that does not have a backing class factory." Message = "COM object that has been separated from its underlying RCW cannot be used." – Muhammad Touseef Jun 12 '17 at 10:05
  • I have made the NowPlayingVideo field private and now initializing it through the onnavigatedTo method and I still get the exact same exception. – Muhammad Touseef Jun 12 '17 at 10:22
  • I have edited the question to clarify it even more with my code. @Stefan please see the "Update 3" section of the question. Thanks – Muhammad Touseef Jun 12 '17 at 10:47
  • Thanks a lot for the help I was able to fix the problem by adding following 3 lines before closing the window. Media.TransportControls = null; Media.Source = null; NowPlayingVideo = null; Do you know the reason why this fixed my issue? – Muhammad Touseef Jun 12 '17 at 10:57
  • If you could provide a repro project that demonstrates the behavior we can take a look. Thanks! – Stefan Wick MSFT Jun 12 '17 at 13:27