App Lifecycle

How ViewModels Are Creating in MugenMvvm

MugenMvvm viewmodel creation supports the next features:

  • constructor based Dependency Injection
  • saving and reloading VM state (await/async operations are supported too).

In MugenMvvm viewModel creation is controlled by IViewModelProvider interface:

public interface IViewModelProvider
{
  IViewModel GetViewModel(GetViewModelDelegate<IViewModel> getViewModel,    
                          IDataContext dataContext);

  IViewModel GetViewModel(Type viewModelType, IDataContext dataContext);

  void InitializeViewModel(IViewModel viewModel, IDataContext dataContext);

  IDataContext PreserveViewModel(IViewModel viewModel, IDataContext dataContext);

  IViewModel RestoreViewModel(IDataContext viewModelState, 
                           IDataContext dataContext, bool throwOnError);

  IViewModel TryGetViewModelById(Guid viewModelId);

  IList<IViewModel> GetCreatedViewModels(IDataContext dataContext = null);

  event EventHandler<IViewModelProvider, ViewModelInitializationEventArgs> Initializing;

  event EventHandler<IViewModelProvider, ViewModelInitializationEventArgs> Initialized;

  event EventHandler<IViewModelProvider, ViewModelPreservingEventArgs> Preserving;

  event EventHandler<IViewModelProvider, ViewModelPreservedEventArgs> Preserved;

  event EventHandler<IViewModelProvider, ViewModelRestoringEventArgs> Restoring;

  event EventHandler<IViewModelProvider, ViewModelRestoredEventArgs> Restored;
}

You can add your own implementation or inherits default MugenMvvm implementation.

ViewModel Construction

In MugenMvvm a typed viewmodel instance can be obtained by GetViewModel method:

private async Task OpenOrder()
{
  using (var vm = GetViewModel<OrderViewModel>())
  {
    // fill any properties of viewmodel if needed
    // e.g. vm.UserName = GetCurrentUserName();
    await vm.ShowAsync();
  }
}
public class OrderWorkspaceViewModel : EditableViewModel<OrderModel>
{        
  private readonly IRepository _repository;        

  public OrderWorkspaceViewModel(IRepository repository)
  {
    Should.NotBeNull(repository, "repository");

    _repository = repository;
  }
}

GetViewModel will do dependency injection if needed. Dependency Injection is, of course, optional.
When viewmodel constructor finish his work viewmodel initialization process is started. Through initialization two methods will be called one by one: OnInitializing and OnInitialized. Any of these methods can be overridden in viewmodel inheritors:

public class OrderWorkspaceViewModel : EditableViewModel<OrderModel>, IHasState
{        
  // ... constructors and fields
  
  protected override void OnInitializing(IDataContext context)
  {
    // do work precedes the initialization
  }
  
  protected override void OnInitialized()
  {
     // do work succeeds the initialization
  }
  
  // ...
}

State Restoration

If the ViewModel is recovering from a tombstoned state then state restoration will be provided with the data needed for rehydration.

In order to support state save/restoration the viewmodel has to implement IHasState interface interface:

public interface IHasState
{
  void LoadState([NotNull] IDataContext state);

  void SaveState([NotNull] IDataContext state);
}

Let's look at an example. Presented below is the example of how IHasState interface can be used to save/restore the state of viewmodel:

public class OrderWorkspaceViewModel : EditableViewModel<OrderModel>
{        
  private static readonly DataConstant<ViewModelState> StateConstant;

  static OrderEditorViewModel()
  {
    StateConstant = DataConstant.Create(() => StateConstant, true);
  }
  
  // ... other constructors and fields
  
  // ... initialization code
  
  public async void LoadState(IDataContext state)
  {
    var viewModelState = state.GetData(StateConstant);
    if (viewModelState == null) return;
    InitializeEntity(viewModelState.Order, viewModelState.IsNewRecord);    
  }

  public void SaveState(IDataContext state)
  {    
    var viewModelState = new ViewModelState 
    { 
      Order = Entity, 
      IsNewRecord = IsNewRecord 
    };            
    state.AddOrUpdate(StateConstant, viewModelState);
  }
  
  // ...
}

In this example we save viewmodel state in SaveState method by using IDataContext and typed constant StateContstant. When LoadState method is called it restores viewmodel state by invoking the InitializeEntity method.

The most powerful feature of MugenMvvm state restoration is ability to save/restore task-based asynchronous operations (async/await). It means that if application is tombstoned it will be correctly restored including all async/await operations. Let's look at example.

private async Task OpenOrder()
{
  using (var vm = GetViewModel<OrderViewModel>())
  {
    // fill any properties of viewmodel if needed
    // e.g. vm.UserName = GetCurrentUserName();
    await vm.ShowAsync();
    
    // here our app is tombstoned....
    
    // here we want to do something important
    if (vm.SelectedOrder != null)
    {
       // do something really important
    }
  }
}

If application is tombstoned in the moment when ShowAsync is executed MugenMvvm will handle it and save/restore viewmodel in correct way.

iOS: State Restoration

In order to control save/restore mechanism work use the next "AppDelegate.cs" methods:

[Register("AppDelegate")]
    public class AppDelegate : MvvmAppDelegateBase
    {
        #region Methods

        protected override TouchBootstrapperBase CreateBootstrapper(UIWindow window)
        {
            return new Bootstrapper<App>(window, new MugenContainer());
        }
      
        public override bool ShouldRestoreApplicationState(UIApplication application, NSCoder coder)
        {
            return base.ShouldRestoreApplicationState(application, coder);
        }

        public override bool ShouldSaveApplicationState(UIApplication application, NSCoder coder)
        {
            return base.ShouldSaveApplicationState(application, coder);
        }

        #endregion
    }

UWP: State Restoration

In order to control save/restore mechanism work use the next "App.cs" methods:

sealed partial class App : MvvmUwpApplicationBase
    {
        #region Methods

        protected override UwpBootstrapperBase CreateBootstrapper(Frame frame)
        {
            return new Bootstrapper<Portable.App>(frame, new MugenContainer(), new[]
            {
                typeof(App).GetTypeInfo().Assembly,
                typeof(MainViewModel).GetTypeInfo().Assembly
            });
        }

        protected override bool ShouldSaveApplicationState()
        {
            return base.ShouldSaveApplicationState();
        }

        protected override bool ShouldRestoreApplicationState()
        {
            return base.ShouldRestoreApplicationState();
        }
      
        protected override Task RestoreStateAsync(LaunchActivatedEventArgs args)
        {
						return base.RestoreStateAsync(args);
        }

        protected override Task SaveStateAsync(SuspendingEventArgs args)
        {
          	return base.SaveStateAsync(args);
        }

        #endregion
    }

Xamarin.Forms: State Restoration

In order to control save/restore mechanism work use the next "App.cs" methods:

public class App : MvvmXamarinApplicationBase
    {
        #region Constructors

        public App(XamarinFormsBootstrapperBase.IPlatformService platformService) : base(platformService)
        {
        }

        #endregion

        #region Methods

        protected override XamarinFormsBootstrapperBase CreateBootstrapper(XamarinFormsBootstrapperBase.IPlatformService platformService, IDataContext context)
        {
            return new Bootstrapper<Portable.App>(platformService, new MugenContainer());
        }
      
        protected override bool ShouldSaveApplicationState()
        {
            return base.ShouldSaveApplicationState();
        }

        protected override bool ShouldRestoreApplicationState()
        {
            return base.ShouldRestoreApplicationState();
        }

        #endregion
    }