We have a windows phone 8 application in which we are using mvvm light having four , five views , and about same number of view models. One day we observed that the size of the application is increasing with usage and eventually reaches more than 100 mb and eventually crashes.After lot of testing what we are able to understand is that every time we navigate to a view , its instance is created and stored in the memory.It was observed that all the instances of the view and the view model are living in the memory and thus increasing the space on the ram. We also confirmed the same by defining finializer on view class and view model , on closing the application the finializer is called exactly the same number of times the page was navigated to. We are binding the datacontext of the view to respective view model in xaml. One of the main view has an ad control , so size increases very fast if user navigates to that view multiple times. How to resolve this issue. What I am unable to understand is the view should be destroyed once the user presses the back button, but this is not happening . Any help would be much appreciated.
We found a solution to this by adding below line of code to code behind.
protected override void OnNavigatedFrom(NavigationEventArgs e)
{
base.OnNavigatedFrom(e);
Messenger.Default.Unregister(this);
if (e.NavigationMode == NavigationMode.Back)
{
DataContext = null;
}
}
What we are doing above is that we are unregisterring all the message handlers for the page and assigning the DataContext to null. In our case the datacontext was assigned in the xaml only and messenge handlers were registered in the OnNavigatedTo event of the page. But what is still unclear that on navigating back from the page , the page object should have died automatically . And should this line of code be added to all the mvvm light project pages and if so then why is it not common practice.
The reason you are leaking View memory is because you are in some way subscribing to events of the ViewModel from inside your Views. Either refactor those subscriptions to be WeakEvent subscriptions or remove them inside your OnNavigatedFrom
Use an IOC Container to maintain a single instance of all the ViewModels.
One of the options would be to use SimpleIoc that comes with MVVM Light.
Best tutorial to learn MVVMLight SimpleIoc
Related
I have a command that shows a view model:
private void DoShowImportCommand()
{
this.ShowViewModel<GeometryImportViewModel>();
}
but I only want to execute it if that view model isn't already shown. Is there a way to
detect if that view model is already on screen and if so don't execute the command?
MvvmCross doesn't track this by default - what is currently shown depends on the UI and can be interpreted in different ways in different situations (popups, tabs, pivots, dialogs, back stacks, etc)
If you want to track this in your own application, you could do it using UI project components (e.g. custom presenters) or you could do it using a shared code component - e.g. you could add "alive" tracking to the Views/ViewModels (see the N=42 video on http://mvvmcross.blogspot.com) and could then use some service to track which viewmodels are shown.
In my Windows Phone App there's a simple hierarchical model consisting of a class containing a collection of other domain objects.
In my xaml i have declared an ItemsContainer control that renders the items in the above mentioned collection as simple rectangles.
Now, at the VM level i have a structure that resembles my model with a parent VM having a collection of children VMs. Each child-VM encapsulates its own model.
Whenever the user taps the view bound to a child-VM a method of the parent-model object should be invoked taking the relevant child-model as parameter. This will in turn change some internal state that will be reflected (possibly) on all the child-views (not just the tapped one).
SO... given that i'm using the MVVM Light framework my current implementation is as follows:
Child-VM exposes a command
The command Execute method will use the messenger to notify the parent-VM of the tap event. The message (GenericMessage class) content will be the domain object encapsulated by the VM
The parent-VM executes the method of the parent-model using the message content as parameter
If the operation succeeds the parent-VM sends a new message to inform child-VMs of this fact. Once again the message content is the model object used as parameter in the method that was just invoked
Child-VMs raise a couple of PropertyChanged events that, finally, will update the bound views
It works but i fill it's a bit cumbersome. The thing that bugs me the most is the fact that when a child-view is tapped the associated VM will broadcast its encapsulated model object. Do you feel that there would be a better way of implementing such a system?
Thanks in advance for your precious help
Could you not just put the command on the parent viewmodel and pass the child viewmodel as the command parameter?
The parent view model can then just call methods on the child viewmodels to update them. I'm not sure I see the need for all these messages?
I am trying to understand how MvvmCross manages memory on Windows Phone.
I try to mark my view and viewmodel as IDisposable, but the Dispose method is never called.
What I need to do is to make sure that I can free up some resources while my app is running location tracking in the background.
Christian
In MvvmCross:
each View references its ViewModel
the platform-specifiic operating system decides when to dereference the View - when this occurs it normally calls a method on the View (but this does depend on whether the view is a page, a tab, a flyout, a dialog, a custom control, etc)
the .Net or Mono Garbage Collector then decides when to collect both the Views and ViewModels from memory
If you want to do more "active" monitoring of when the View is visible for "page-level" Views, then you need to monitor "page-level" View-specific events like:
ViewDidAppear \ ViewDidDisappear \ removeFromParentViewController (iOS)
OnResume \ OnPause`OnFinish` (Droid)
OnNavigatedTo`OnNavigatedFrom` (Windows)
A generalised form of these events can then be easily called on a custom interface on your ViewModel (this can be IDisposable if you want - this is your application code).
Update: I have blogged about this and published a sample - see http://slodge.blogspot.co.uk/2013/11/n42-is-my-viewmodel-visible-can-i-kill.html
There's a bit more info on this in:
ViewModel LifeCycle, when does it get disposed? (see "There's no easy universal way to know when to dispose the ViewModel - especially once you start mixing and matching ViewModel presentation styles to include navigations, tabs, splitviews, flyouts, fragments, lists, etc. and as you include more and more platforms")
https://github.com/MvvmCross/MvvmCross/wiki/View-Model-Lifecycle#viewmodel-deactivation-activation-and-destruction
I am building a WinRT App, that uses proximity, and WiFi direct for peer to peer communication. As a result, when the app terminates, and then resumes I need it to start fresh (the connections will be closed, and can't be reopened without user interaction). The problem is that the Prism MvvmAppBase class that I am inheriting my app from is doing something that is causing it to try to resume from a saved state (that does not exist) and the app ends up on the last screen shown, but there is no ViewModel backing it, and so depending on the view, it will just sit unresponsive, or crash.
I am looking at this guide for guidance, and it says that unless there is a way to start fresh, but I cannot seem to find how to actually do that. http://msdn.microsoft.com/en-us/library/windows/apps/xx130647.aspx
I have been hacking around in the App.cs file to try and get it to work. There is really nothing at all in the App.cs file now except for the unity container and prism bootstrapping, and a call to NavigationService.Suspending() in the Suspending event handler.
The bootstrapping looks like this, but it is never called when the app is resumed from Termination.
protected override async void OnLaunchApplication(LaunchActivatedEventArgs args)
{
await BootStrapper.Config(_container);
await BootStrapper.RegisterPrismInstances(_container, NavigationService, SessionStateService, FlyoutService);
NavigationService.Navigate("Main", null);
}
If anyone has dealt with this before, and can point me in the right direction, I would really appreciate it.
When a Prism WinRT app is re-launched after being Terminated Prism will try to restore the application state, the Frame's navigation stack and the Frame's state before being terminated (which will navigate to the last opened page and try to restore any properties in the view model that are marked with the RestorableState attribute.)
By looking at the MvvmAppBase's source code it seems that there are a couple of things you could try to prevent Prism for saving / restoring the application state:
Create a default constructor in your App class that would clear the handlers of the Suspending event. The default constructor of the MvvmAppBase registers to this event and saves the state when it's raised.
Override the OnLaunched method of the base class. In it, after executing the base method, check if the previous executing state is Terminated. If so, you could clear the navigation history of the NavigationService and navigate to your start up page. The saving and restoring operations will still execute though, so any registered service will still be restored to its previous state. (This cannot be done in the OnLaunchApplication as it's not invoked if the application's state was successfully restored.)
Also, you could also try to completely remove this functionality from the MvvmAppBase class. However, most of its methods related to saving / restoring the application state are private, so you might as well drop the MvvAppBase, copy its entire code in your App class and edit it accordingly.
I have not tried any of the approaches listed above so I'm unaware if they could generate any problem, but they might help you as a starting point.
This question is a follow-up / "second attempt" to a previous question of mine.
I am building a cross-platform mobile application using MvvmCross framework,
and I would like to use the Messenger plugin to receive event notifications published from somewhere else in my code.
I have tried to add the subscription in the ctor as follows:
public class MyViewModel : BaseViewModel, IMyViewModel
{
private MvxSubscriptionToken _showMsgToken;
public MyViewModel ()
{
_showMsgToken = MvxMessenger.Subscribe<ShowMsg>(message => onShowNavigation(), MvxReference.Weak);
}
private void onShowNavigation()
{
//Do Stuff
}
}
Now when I navigate to this ViewModel everything works and notifications are received.
However, when I navigate away and back to this ViewModel, I can see that the Subscription is adding another entry to the MvxMessenger subscriptions property, resulting onShowAdsNavigation() firing twice for each new event.
So, How can I subscribe to events in the ViewModel?
Or maybe I need to find a way to Unsubscribe from events?
If you need to actively unsubscribe from messages, then you can do this by capturing lifetime events within your views and then using these to drive your viewmodel. This is your code - you can do what you like.
For some options on this, see ViewModel LifeCycle, when does it get disposed?
I generally don't bother with active management of subscriptions. Instead I rely on the fact that the View will be removed from the UI, and so it and its ViewModel will be removed from memory at some time afterwards. When this happens I know that the subscription management will then happen automatically - when the View and ViewModel get Garbage Collected, then the subscriptions will also shortly afterwards get cleaned up. I know that the weak referencing used within the Messenger will mean that the subscriptions will clean themselves up.
To prove this, try https://github.com/slodge/MessengerHacking - it has a button to force GC to occur.
If this isn't "good enough* for your app, then see "If you need to actively..." above.