How to Remove A View From Memory When Closed.

Topics: Prism v4 - Silverlight 4
Sep 29, 2010 at 4:06 PM

Hi All,

I have a view which is loaded from a module using prism (set to onDemand). When I close the form with an X on the top left the following method i wrote is invoked..

 

   public void CloseCommand(object Object)
   {
            IRegion region = regionManager.Regions[RegionNames.MainRegion];
            Control viewToLoad = region.GetView(viewName) as Control;
            region.Remove(viewToLoad);
   }

 

While this successfully removes the view from the region manager it does not remove it from memory. The DeConstructor on my view is never called. In fact if i open and close the view several times i can see new objects are being created and memory keeps going up.

The view is a added to a grid in my shell project..

 

<Grid x:Name="MainRegion" prism:RegionManager.RegionName="MainRegion" Margin="8"/>

I suspect the view should also be removed from this grid but i do not know how to access the grid from the calling view..

Whats the best way to correctly remove views from memory to avoid this problem?

 

 

 

 


Sep 29, 2010 at 6:32 PM
Edited Sep 29, 2010 at 6:41 PM

Hi,

Thanks for reporting that, since it might help to users with similar scenarios. The approach that you used for removing the view seems to be correct.

On the other hand, if you do not have any other reference to the views in your application, they should be removed when the garbage collection occurs. But this is not possible to predict when it will occur. Probably, this is why you are seeing that your memory are going up.

I would recommend you to try adding a button (in the toolbar of your app) that force to collect to the garbage collector using the following code:

public void YourButtonClickCommand(object Object)
{
GC.Collect();


}

Then if after executing this code you realize that your memory is released, it means that you do not have a leak over there. But if this does not release, I would recommend you to check if your application keeps a reference of your views (e.g. your region).

Please take into account that this is just a test. After this test, you have to remove this from your application.

If you continue experiencing this situation, could you send a repro sample?.

I hope this help.

Fernando Antivero
http://blogs.southworks.net/fantivero

Sep 29, 2010 at 6:49 PM

Hi,

I think it is the Grid object (my region) which is keeping ahold of the object. I believe I have solved it now by creating a GridAdaptor which can add and remove objects from the grid.

1) In Bootstraper.cs I added

RegionAdapterMappings mappings = base.ConfigureRegionAdapterMappings();
mappings.RegisterMapping(typeof(Grid), Container.Resolve<GridRegionAdapter>());
return mappings;

2) In GridRegionAdaptor.cs I added code to handle the added and remove of views

using System;
using System.Collections.Specialized;
using System.Windows;
using System.Windows.Controls;
using Microsoft.Practices.Prism.Regions;

namespace Infor.Common.RegionAdapters
{
/// <summary>
/// Used to Assist in Selecting Rows in the Dual List Exchange.
/// </summary>
public class GridRegionAdapter : RegionAdapterBase<Grid>
{
/// <summary>
/// Initializes a new instance of <see cref="GridRegionAdapter"/>.
/// </summary>
/// <param name="regionBehaviorFactory">The factory used to create the region behaviors to attach to the created regions.</param>
public GridRegionAdapter(IRegionBehaviorFactory behaviorFactory) :
base(behaviorFactory)
{ }

/// <summary>
/// Adapts a <see cref="Grid"/> to an <see cref="IRegion"/>.
/// </summary>
/// <param name="region">The new region being used.</param>
/// <param name="regionTarget">The object to adapt.</param>
protected override void Adapt(IRegion region, Grid regionTarget)
{
region.Views.CollectionChanged += (s, e) =>
{
//Add
if (e.Action == NotifyCollectionChangedAction.Add)
{
foreach (FrameworkElement element in e.NewItems)
{
regionTarget.Children.Add(element);
}
}

//Removal
if (e.Action == NotifyCollectionChangedAction.Remove)
{
// regionTarget.Children.Remove(element);
foreach (FrameworkElement element in e.OldItems)
{
regionTarget.Children.Remove(element);
}
               }
};
}

/// <summary>
/// Creates a new instance of <see cref="Region"/>.
/// </summary>
/// <returns>A new instance of <see cref="Region"/>.</returns>
protected override IRegion CreateRegion()
{
return new Region();
}
}
}

After implementing this memory goes down and the deconstructor is called for my view..

HTH Others..

Thanks

From: fantivero [mailto:notifications@codeplex.com]
Sent: Wednesday, September 29, 2010 1:33 PM
To: Tim James McConechy
Subject: Re: How to Remove A View From Memory When Closed. [CompositeWPF:229036]

From: fantivero

Hi,

Thanks for reporting that, since it might help to users with similar scenarios. The approach that you used for removing the view seems to be correct.

On the other hand, if you do not have any other reference to the views in your application, they should be removed when the garbage collection occurs. But this is not possible to predict when it will occur. Probably, this is why you are seeing that your memory are going up.

I would recommend to you to try adding a button (in the toolbar of your app) to force to collect to the garbage collector using the following code:

public void YourButtonClickCommand(object Object)
{
    GC.Collect();


}

Then if after executing this code you realize that your memory is released, it means that you do not have a leak over there. But if this does not release, I would recommend you to check if your application is keeping a reference of your views (e.g. your region).

If you continue experiencing this situation, you could send a repro sample of your scenario.

I hope this help.

Fernando Antivero
http://blogs.southworks.net/fantivero

Read the full discussion online.

To add a post to this discussion, reply to this email (CompositeWPF@discussions.codeplex.com)

To start a new discussion for this project, email CompositeWPF@discussions.codeplex.com

You are receiving this email because you subscribed to this discussion on CodePlex. You can unsubscribe on CodePlex.com.

Please note: Images and attachments will be removed from emails. Any posts to this discussion will also be available online at CodePlex.com

Sep 29, 2010 at 6:53 PM
Edited Sep 29, 2010 at 6:53 PM

Hi,

Thanks for sharing your findings with the rest of the community, since it is really valuable. Nice to see that you solved this scenario.

Fernando Antivero
http://blogs.southworks.net/fantivero

 

Nov 24, 2010 at 6:12 AM

Hi Fernando,

I have the same GridRegionAdapter in my application. The way I handle swithcing views in a region is using RequestNavigate (which implies I'm using MEF).

Problem is the grid region adapter doesnt seem to get called for "Remove" action because I never call the region.Remove(view) and it piles up views on top of each other.

I thought this should have been handled by the RegionManager.RequestNavigate. I have my views decorated with [RegionMemberLifetime(KeepAlive = false)] which ideally should have invoked the remove action when navigated away from.

Is my understanding incorrect or should I be explicitly calling a region.Remove to invoke the Remove action so that my GridRegionAdapter captures it?

Thanks.

Nov 24, 2010 at 6:27 AM

Hi fernando,

I found the solution myself. I changed the following

protected override IRegion CreateRegion()
{
return new Region();
}

to

protected override IRegion CreateRegion()
{
return new SingleActiveRegion();
}

and it works well now.