EntireGraph<TService> in StorageHandler<T>

Topics: Framework Services
Jul 11, 2011 at 12:17 PM

Hi,

I am using caliburn framework to build windows phone 7 application.

I am using  StorageHandler<T> to store the state during tombstoning. 

Currently i am storing Individual property using Property of  StorageHandler<T> class. This will help me to store a single Property.

Now i want to know ,how to use EntireGraph<TService> ?

What is the syntax & how can it be helpful to recover the screen from tombstoning ?

Coordinator
Jul 11, 2011 at 1:15 PM
Edited Jul 11, 2011 at 1:18 PM

By calling EntireGraph, you instruct the storage handler to persist the entire instance, rather than just saving individual properties. To do this, the entire instance must be serializable. Here's is how the method is implemented:

 

      public StorageInstructionBuilder<T> EntireGraph<TService>(string storageKey = "ObjectGraph") {
            return AddInstruction().Configure(x => {
                x.Key = storageKey;
                x.Save = (instance, getKey, mode) => x.StorageMechanism.Store(getKey(), instance);
                x.Restore = (instance, getKey, mode) => { };
                x.PropertyChanged += (s, e) => {
                    if(e.PropertyName == "StorageMechanism" && x.StorageMechanism != null) {
                        x.StorageMechanism.RegisterSingleton(typeof(TService), GetKey(default(T), x.Key), typeof(T));
                    }
                };
            });
        }

As you can see, calling this method instructs the storage mechanism to persist the entire instance. It also tells the storage mechanism to register the instance with the the IoC container as a singleton. So, when it's restored, if it is coming from the IoC container, the container will actually look in the storage mechanism to find the instance. The key is used by the storage mechanism internally.

Coordinator
Jul 11, 2011 at 1:17 PM

Also, the generic parameter, TService, can be used to specify an interface to use as part of the registration process.

Jul 11, 2011 at 1:35 PM

Firstly, thank you for replying so fast.

What is the syntax to call EntireGraph method ? 

ie for using Property i use this statement
  Property(x => x.Company).InPhoneState().RestoreAfterActivation();

where company is a property name which i want to persist.

In the same way if i need to use  EntireGraph method  what should i pass ?

Coordinator
Jul 11, 2011 at 2:19 PM

You pass nothing. If you have the class:

public class MyViewModel { ... }

Then you have the handler:

public class MyViewModelStorage : StorageHandler<MyViewModel>{

   public override Configure(){

      EntireGraph<MyViewModel>().InPhoneState();

   }

}

The re-hydration mechanism is registered with the IoC container, so anytime MyViewModel is requested from the container, either manually or through ctor injection, it will retrieve it from the IoC container. When the phone tombstones, it will put the entire instance in phone state.

Jul 11, 2011 at 2:39 PM
Edited Jul 11, 2011 at 3:07 PM

Ya i tried this 

I have  public class ProductPageViewModel : Conductor<IScreen>.Collection.OneActive    {    }

Then i have handler    public class ProductPageModel : StorageHandler<ProductPageViewModel>    {
                 public override void Configure() {

  EntireGraph<ProductPageViewModel>().InPhoneState();

}

But when i am navigating to this View , I get an expection in SimpleContainer.cs GetInstance(Type service, string key) method.

Exception is "Sequence contains more than one element" (InvalidOperationException) when executing

 return entry.Single()(this);

Am i doing something wrong ?

Should i do something to make instance serializable ?

Jul 11, 2011 at 3:09 PM

This is the stack trace

at System.Linq.Enumerable.Single[TSource](IEnumerable`1 source)   at Caliburn.Micro.SimpleContainer.GetInstance(Type service, String key)   at IndienceOrdersApp.IndienceOrdersAppBootstrapper.GetInstance(Type service, String key)   at Caliburn.Micro.ViewModelLocator.<.cctor>b__8(Type viewType)   at Caliburn.Micro.ViewModelLocator.<.cctor>b__9(Object view)   at Caliburn.Micro.FrameAdapter.OnNavigated(Object sender, NavigationEventArgs e)   at System.Windows.Navigation.NavigationService.RaiseNavigated(Object content, Uri uri, NavigationMode mode, Boolean isNavigationInitiator, PhoneApplicationPage existingContentPage, PhoneApplicationPage newContentPage)   at System.Windows.Navigation.NavigationService.CompleteNavigation(DependencyObject content, NavigationMode mode)   at System.Windows.Navigation.NavigationService.ContentLoader_BeginLoad_Callback(IAsyncResult result)   at System.Windows.Navigation.PageResourceContentLoader.BeginLoad_OnUIThread(AsyncCallback userCallback, PageResourceContentLoaderAsyncResult result)   at System.Windows.Navigation.PageResourceContentLoader.<>c__DisplayClass4.<BeginLoad>b__0(Object args)   at System.Reflection.RuntimeMethodInfo.InternalInvoke(RuntimeMethodInfo rtmi, Object obj, BindingFlags invokeAttr, Binder binder, Object parameters, CultureInfo culture, Boolean isBinderDefault, Assembly caller, Boolean verifyAccess, StackCrawlMark& stackMark)   at System.Reflection.RuntimeMethodInfo.InternalInvoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture, StackCrawlMark& stackMark)   at System.Reflection.MethodBase.Invoke(Object obj, Object[] parameters)   at System.Delegate.DynamicInvokeOne(Object[] args)   at System.MulticastDelegate.DynamicInvokeImpl(Object[] args)   at System.Delegate.DynamicInvoke(Object[] args)   at System.Windows.Threading.DispatcherOperation.Invoke()   at System.Windows.Threading.Dispatcher.Dispatch(DispatcherPriority priority)   at System.Windows.Threading.Dispatcher.OnInvoke(Object context)   at System.Windows.Hosting.CallbackCookie.Invoke(Object[] args)   at System.Windows.Hosting.DelegateWrapper.InternalInvoke(Object[] args)   at System.Windows.RuntimeHost.ManagedHost.InvokeDelegate(IntPtr pHandle, Int32 nParamCount, ScriptParam[] pParams, ScriptParam& pResult)

Coordinator
Jul 11, 2011 at 3:22 PM

Well, Conductors aren't really designed to be serialized. You should probably extract the state that is important into its own object and serialize that instead.

Jul 11, 2011 at 3:29 PM

Is there any example in which EntireGraph method is being used?

Coordinator
Jul 11, 2011 at 5:17 PM

No current examples. I can try to add something to the WP7 sample that demonstrates that. I can't make any promises on timeline for that though.

Jul 12, 2011 at 6:50 AM

OK ,Please update me if the sample is added , which demonstrate the use of EntireGraph.

Thank you once again.