简体   繁体   中英

UWP C# Cleaning up secondary page

I'm opening a secondary UWP page, and which is essentially detail of an item clicked on the main page. However, when closing the secondary page, the memory is not returned, nor do I see a close event I can utilize in order to attempt to dispose or GC. Each time opening a secondary page may takes up to 15MB depending on the level of detail. If I open/close 20 pages, I've wasted 250MB that I can't seem to reclaim.

The code to open the new page is:

        CoreApplicationView newView = CoreApplication.CreateNewView();
        int newViewId = 0;
        await newView.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
        {

            Frame frame = new Frame();
            frame.Navigate(typeof(Disk), null);                
            Window.Current.Content = frame;
            Window.Current.Activate();
            newViewId = ApplicationView.GetForCurrentView().Id;
        });
        bool viewShown = await ApplicationViewSwitcher.TryShowAsStandaloneAsync(newViewId);

There is nothing in my main page's frame.BackStack. Is there any way to use the "newViewId" to find the frame and remove or destroy it to reclaim the memory?

The Windows 10SDK had the answer in their Multiple Views example: https://github.com/Microsoft/Windows-universal-samples/tree/master/Samples/MultipleViews

A few edits will be necessary to get everything working appropriately within your namespaces etc.

1) Add to the App.cs

    partial void Construct();

    // Hook into OnLaunched here.
    partial void OverrideOnLaunched(LaunchActivatedEventArgs args, ref bool handled);

    // Hook into InitializeMainPage here.
    partial void InitializeRootFrame(Frame frame);

2) Implement the SampleConfigurations.cs class file from the SDK and update to your namespace. You only need to implement the class App and it essentially adds a few functions and objects to class App essentially it creates a dispatcher and a collection of SecondaryViews for use later.

3) Implement the ViewLifetimeControls.cs as is which will control your secondary views (its namespace is SecondaryViewsHelpers and implements the events and functions necessary for keeping track of the secondary views and destroying the objects when closing.

4) Add using using SecondaryViewsHelpers; to the page that will be launching the secondary view. To launch the secondary view use the below code:

        ViewLifetimeControl viewControl = null;
        await CoreApplication.CreateNewView().Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
        {
            // This object is used to keep track of the views and important
            // details about the contents of those views across threads
            // In your app, you would probably want to track information
            // like the open document or page inside that window
            viewControl = ViewLifetimeControl.CreateForCurrentView();
            viewControl.Title = "";
            // Increment the ref count because we just created the view and we have a reference to it                
            viewControl.StartViewInUse();

            var frame = new Frame();
            frame.Navigate(typeof(SecondaryPage), viewControl);
            Window.Current.Content = frame;
            // This is a change from 8.1: In order for the view to be displayed later it needs to be activated.
            Window.Current.Activate();
            ApplicationView.GetForCurrentView().Title = viewControl.Title;
            ((App)App.Current).SecondaryViews.Add(viewControl);
        });
        bool viewShown = await ApplicationViewSwitcher.TryShowAsStandaloneAsync(viewControl.Id, ViewSizePreference.Default, ApplicationView.GetForCurrentView().Id, ViewSizePreference.Default);

5) On the secondary page, you'll need to reference, using SecondaryViewsHelpers; and declare the below objects/variables:

    ViewLifetimeControl thisViewControl;
    int mainViewId;
    CoreDispatcher mainDispatcher;

Add the below code to the secondary page to assign the objects above and register the event

        protected override void OnNavigatedTo(NavigationEventArgs e)
        {
            thisViewControl = (ViewLifetimeControl)e.Parameter;
            mainViewId = ((App)App.Current).MainViewId;
            mainDispatcher = ((App)App.Current).MainDispatcher;
            // When this view is finally released, clean up state
            thisViewControl.Released += ViewLifetimeControl_Released;
        }

        private async void ViewLifetimeControl_Released(Object sender, EventArgs e)
        {
            ((ViewLifetimeControl)sender).Released -= ViewLifetimeControl_Released;
            // The ViewLifetimeControl object is bound to UI elements on the main thread
            // So, the object must be removed from that thread
            await mainDispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
            {
                ((App)App.Current).SecondaryViews.Remove(thisViewControl);
            });

            // The released event is fired on the thread of the window
            // it pertains to.
            //
            // It's important to make sure no work is scheduled on this thread
            // after it starts to close (no data binding changes, no changes to
            // XAML, creating new objects in destructors, etc.) since
            // that will throw exceptions
            Window.Current.Close();
        }

Now when closing the secondary windows, I can see the being given back. My only concern is that this takes over the parameters which I would otherwise send data to the newly created view. I'll have to find a workaround to pass info to the secondary page - maybe using the title temporarily.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM