Created
January 3, 2011 10:08
-
-
Save renestein/763320 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public class PageBase : PhoneApplicationPage | |
{ | |
private List<Object> m_viewModels; | |
public PageBase() | |
{ | |
IsNewInstance = true; | |
WasLayoutUpdateCalled = false; | |
LayoutUpdated += PageBase_LayoutUpdated; | |
m_viewModels = new List<Object>(); | |
} | |
static PageBase() | |
{ | |
ViewModelManager = () => new ViewModelResolver(); | |
} | |
public bool IsNewInstance | |
{ | |
get; | |
set; | |
} | |
public bool WasLayoutUpdateCalled | |
{ | |
get; | |
set; | |
} | |
public static Func<IViewModelResolver> ViewModelManager | |
{ | |
get; | |
set; | |
} | |
public Dictionary<String, Object> LastSavedTransientState | |
{ | |
get; | |
set; | |
} | |
protected override void OnNavigatedTo(NavigationEventArgs e) | |
{ | |
base.OnNavigatedTo(e); | |
WasLayoutUpdateCalled = false; | |
loadSavedTranzientState(); | |
} | |
protected override void OnNavigatedFrom(NavigationEventArgs e) | |
{ | |
base.OnNavigatedFrom(e); | |
SaveState(); | |
handleAllDeactivated(); | |
} | |
private T tryGetTypedViewModel<T>(object obj) | |
where T: class | |
{ | |
return obj as T; | |
} | |
protected virtual void SaveState() | |
{ | |
var statebag = new KnownTypesDictionary(); | |
var rootPair = getRootpair(); | |
saveTransientState(rootPair, statebag, this, null); | |
string stateKey = GetType().FullName; | |
State[stateKey] = statebag; | |
LastSavedTransientState = statebag; | |
} | |
protected virtual void LoadState() | |
{ | |
var rootPair = getRootpair(); | |
restoreTransientState(rootPair, this, null); | |
} | |
private ElementIndexPair getRootpair() | |
{ | |
var rootPair = new ElementIndexPair | |
{ | |
Element = this, | |
Parent = null, | |
Index = 0 | |
}; | |
return rootPair; | |
} | |
private void saveTransientState(ElementIndexPair pair, Dictionary<string, Object> stateBag, FrameworkElement root, Object lastDataContext) | |
{ | |
if (ViewModelManager().IsView(pair.Element)) | |
{ | |
var stateManager = getStateManager(pair.Element.DataContext); | |
if (stateManager != null && stateManager != lastDataContext) | |
{ | |
lastDataContext = stateManager; | |
saveStateInner(pair, stateBag, root, stateManager); | |
} | |
} | |
UIHelper.GetChildren(pair.Element) | |
.ToList() | |
.ForEach(elementPair => | |
{ | |
elementPair.Parent = pair; | |
saveTransientState(elementPair, stateBag, root, lastDataContext); | |
}); | |
} | |
private void saveStateInner(ElementIndexPair pair, Dictionary<string, Object> stateBag, FrameworkElement root, ITransientStateManager stateManager) | |
{ | |
var state = stateManager.SaveState(); | |
if (state != null) | |
{ | |
var stateKey = UIHelper.GetTransientStateKey(pair, root); | |
stateBag[stateKey] = state; | |
} | |
} | |
private void restoreTransientState(ElementIndexPair pair, FrameworkElement root, Object lastViewModel) | |
{ | |
if (ViewModelManager().IsView(pair.Element)) | |
{ | |
string stateKey = UIHelper.GetTransientStateKey(pair, root); | |
bool hasSavedState = LastSavedTransientState != null && | |
LastSavedTransientState.ContainsKey(stateKey); | |
Object currentViewModel = prepareViewModel(pair.Element); | |
var stateManager = getStateManager(currentViewModel); | |
var initObject = getInitObjectWithSyncContext(currentViewModel); | |
lastViewModel = selectViewModel(pair.Element, lastViewModel, currentViewModel); | |
SendOrPostCallback setDataContext = _ => pair.Element.DataContext = lastViewModel; | |
if (stateManager != null && hasSavedState) | |
{ | |
stateManager.LoadState(LastSavedTransientState[stateKey]); | |
} | |
else if (initObject != null) | |
{ | |
initObject.Init(); | |
} | |
activateAndSetDataContext(currentViewModel, setDataContext); | |
} | |
UIHelper.GetChildren(pair.Element) | |
.ToList() | |
.ForEach(elementPair => | |
{ | |
elementPair.Parent = pair; | |
restoreTransientState(elementPair, root, lastViewModel); | |
}); | |
} | |
private void activateAndSetDataContext(object viewModel, SendOrPostCallback setDataContext) | |
{ | |
notifyActivated(viewModel); | |
SynchronizationContext.Current.Send(_ => setDataContext(null), null); | |
} | |
private object selectViewModel(FrameworkElement element, Object lastViewModel, Object currentViewModel) | |
{ | |
if (currentViewModel != null) | |
{ | |
storeViewModel(currentViewModel); | |
return currentViewModel; | |
} | |
else | |
{ | |
return lastViewModel; | |
} | |
} | |
private void storeViewModel(Object viewModel) | |
{ | |
m_viewModels.Add(viewModel); | |
} | |
private void loadSavedTranzientState() | |
{ | |
LastSavedTransientState = null; | |
Object savedState; | |
State.TryGetValue(GetType().FullName, out savedState); | |
LastSavedTransientState = savedState as Dictionary<String, Object>; | |
} | |
private IInitialize getInitObjectWithSyncContext(Object obj) | |
{ | |
var initObject = tryGetTypedViewModel<IInitialize>(obj); | |
if (initObject != null) | |
{ | |
initObject.SynchContext = SynchronizationContext.Current; | |
} | |
return initObject; | |
} | |
private object prepareViewModel(Object obj) | |
{ | |
return ViewModelManager().ResolveViewModel(obj); | |
} | |
private ITransientStateManager getStateManager(Object obj) | |
{ | |
var stateManager = obj as ITransientStateManager; | |
return stateManager; | |
} | |
private void PageBase_LayoutUpdated(object sender, EventArgs e) | |
{ | |
handleLayoutUpdated(); | |
} | |
private void handleLayoutUpdated() | |
{ | |
if (WasLayoutUpdateCalled) | |
{ | |
return; | |
} | |
if (IsNewInstance) | |
{ | |
LoadState(); | |
IsNewInstance = false; | |
} | |
else | |
{ | |
handleAllActivated(); | |
} | |
WasLayoutUpdateCalled = true; | |
} | |
private void handleAllActivated() | |
{ | |
m_viewModels.ForEach(notifyActivated); | |
} | |
private void notifyActivated(object obj) | |
{ | |
var activatedItem = tryGetTypedViewModel<IActivated>(obj); | |
if (activatedItem != null) | |
{ | |
activatedItem.Activate(); | |
} | |
} | |
private void handleAllDeactivated() | |
{ | |
m_viewModels.ForEach(notifyDeactivated); | |
} | |
private void notifyDeactivated(object obj) | |
{ | |
var deactivatedItem = tryGetTypedViewModel<IDeactivated>(obj); | |
if (deactivatedItem != null) | |
{ | |
deactivatedItem.Deactivate(); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment