I have a strange recurring problem. Sometimes it goes away, other times it comes back. I can't pinpoint at all the issue, all my breakpoints seem to be hit in expected order.
When I navigate to a new page, my backstack keeps getting deleted, so pressing back just backgrounds the app. Obviously this is a problem.
I think it may be a result of my more complex page and viewmodel structures. I created a new class for all the NavigationHelper stuff for Pages enforcing that all my Pages subclass from the new class. I enforce that all my Pages attach themselves to a base PageViewModel class to resolve the communication between the two (I had a better way but Xaml doesn't play well), and I navigate using a NavigationService, where I call CurrentFrame, which is a static method for return Windows.Current.Content as Frame
.
Here are what I think are relevant code. Any ideas? Thanks a bunch in advance. I have no clue what's going on :/
I navigate forward using the Navigate method in NavigationService (not the other two lolol), but my back button doesn't go back properly.
public abstract class BaseViewModelPage : Page
{
protected readonly NavigationHelper NavigationHelper;
protected BaseViewModelPage()
{
NavigationHelper = new NavigationHelper(this);
NavigationHelper.LoadState += navigationHelper_LoadState;
NavigationHelper.SaveState += navigationHelper_SaveState;
this.NavigationCacheMode = NavigationCacheMode.Required;
}
protected BasePageViewModel CurrentPageViewModel
{
get { return DataContext as BasePageViewModel; }
}
#region Navigation Registration
protected override void OnNavigatedTo(NavigationEventArgs e)
{
NavigationHelper.OnNavigatedTo(e);
}
protected override void OnNavigatedFrom(NavigationEventArgs e)
{
NavigationHelper.OnNavigatedFrom(e);
}
protected virtual void LoadState(LoadStateEventArgs e)
{
if (CurrentPageViewModel != null)
{
CurrentPageViewModel.LoadState(e);
}
}
protected virtual void SaveState(SaveStateEventArgs e)
{
if (CurrentPageViewModel != null)
{
CurrentPageViewModel.SaveState(e);
}
}
private void navigationHelper_LoadState(object sender, LoadStateEventArgs e)
{
LoadState(e);
}
private void navigationHelper_SaveState(object sender, SaveStateEventArgs e)
{
SaveState(e);
}
#endregion
}
public abstract class BasePageViewModel : ViewModelBase
{
private bool _isLoading = false;
public bool IsLoading
{
get
{
return _isLoading;
}
set
{
if (_isLoading == value)
{
return;
}
_isLoading = value;
RaisePropertyChanged();
}
}
public virtual void LoadState(LoadStateEventArgs e)
{
}
public virtual void SaveState(SaveStateEventArgs e)
{
}
}
public class NavigationService : INavigationService
{
public static readonly Dictionary<Type, Type> PageDictionary;
static NavigationService()
{
PageDictionary = new Dictionary<Type, Type>();
PageDictionary.Add(typeof(LogInPageViewModel), typeof(LogInPage));
PageDictionary.Add(typeof(RegisterUserPageViewModel), typeof(RegisterUserPage));
}
public bool Navigate(Type pageViewModelType, Object parameter = null)
{
if (PageDictionary.ContainsKey(pageViewModelType))
{
if (parameter != null)
{
return App.CurrentFrame.Navigate(PageDictionary[pageViewModelType], parameter);
}
else
{
return App.CurrentFrame.Navigate(PageDictionary[pageViewModelType]);
}
}
return false;
}
public bool GoBack()
{
if (CanGoBack())
{
App.CurrentFrame.GoBack();
}
return false;
}
public bool CanGoBack()
{
return App.CurrentFrame.CanGoBack;
}
public bool NavigateAndRemoveSelf(Type pageViewModelType, object parameter = null)
{
if (Navigate(pageViewModelType, parameter))
{
if (App.CurrentFrame.CanGoBack)
{
App.CurrentFrame.BackStack.RemoveAt(App.CurrentFrame.BackStackDepth - 1);
return true;
}
}
return false;
}
public bool NavigateAndRemoveAll(Type pageViewModelType, object parameter = null)
{
if (Navigate(pageViewModelType, parameter))
{
while (App.CurrentFrame.CanGoBack)
{
App.CurrentFrame.BackStack.RemoveAt(App.CurrentFrame.BackStackDepth - 1);
}
return true;
}
return false;
}
}
Update [solved]:
The error is caused by using a Universal App Class Library.
I wanted to separate the NavigationHelper.cs class (generated by default in WP8 apps) into a library. so that I could unit test the VM directly (I could not reference the WP8 app with the Unit Test project). Thus, I placed the NavigationHelper.cs class, plus all my relevant code above, in a new Universal App Class Library.
The NavigationHelper class relies on two things, a WINDOWS_PHONE_APP
macro in the BUILD, which affects this specific part in the NavigationHelper class, the HardwareButton BackPressed listener.
#if WINDOWS_PHONE_APP
Windows.Phone.UI.Input.HardwareButtons.BackPressed += HardwareButtons_BackPressed;
#else
and a second reliance on the Windows.Phone
assembly. The assembly exists in a WP8 app, but not for a Universal App Class Library. This means that even if I add the WINDOWS_PHONE_APP macro to the library, the app will not compile. You cannot use the NavigationHelper generated by Windows Phone 8/8.1 projects inside a Universal App Class Library. I will try to raise this issue. Thanks!
Update [solved]:
The error is caused by using a Universal App Class Library.
I wanted to separate the NavigationHelper.cs class (generated by default in WP8 apps) into a library. so that I could unit test the VM directly (I could not reference the WP8 app with the Unit Test project). Thus, I placed the NavigationHelper.cs class, plus all my relevant code above, in a new Universal App Class Library.
The NavigationHelper class relies on two things, a WINDOWS_PHONE_APP
macro in the BUILD, which affects this specific part in the NavigationHelper class, the HardwareButton BackPressed listener.
#if WINDOWS_PHONE_APP
Windows.Phone.UI.Input.HardwareButtons.BackPressed += HardwareButtons_BackPressed;
#else
...
#endif
Because the MACRO wasn't defined, the back button wouldn't actually go back.
A second problem was the missing Windows.Phone
assembly. The assembly exists in a WP8 app, but not for a Universal App Class Library. This means that even if I add a WINDOWS_PHONE_APP
macro to the library, the app will not compile. You cannot use the NavigationHelper generated by Windows Phone 8/8.1 projects inside a Universal App Class Library. I will try to raise this issue. Thanks!