Final Update
I've have found the problem. It has nothing to do with the backstack manipulation. The cause was a resource dictionary which I didn't registered correctly.
I'm writing a Windows Phone 8.1 App. Because I'm using MVVMcross I have a classic project setup: a portable project which contains the ViewModels and a Windows Phone 8.1 project which contains the Views.
In some cases I want to remove a page from the backstack so that the page before the removed page will be displayed when I click the backbutton.
To achieve this behaviour I have followed alone this example: https://edsnider.net/2014/04/07/clearing-windows-phone-nav-back-stack-in-mvvmcross/
Everything works well except when I do a complete restart while I'm in the app and reopen the app again. In this case I get a COM exception when I do the backstack manipulation:
The operation identifier is not valid.
The BackStack or ForwardStack cannot be changed while navigating.
Question: What is wrong with my code?
Here are the relevant code snippets:
The method DropPageAndShowViewModel is defined in the base class of my ViewModels. The exception occurs when I call this method in a ViewModel:
DropPageAndShowViewModel<TourdatenSummaryViewModel>(
new TourdatenSummaryViewModel.NavObject
{
Tournummer = _tour.Nummer
});
This is the base class of my ViewModels. BaseViewModel derives from MvxViewModel.
public class BasePageViewModel : BaseViewModel
{
...
protected void DropPageAndShowViewModel<TViewModel>()
where TViewModel : BasePageViewModel
{
ShowViewModel<TViewModel>();
ChangePresentation(new DropCurrentBackStackEntryHint());
}
protected void DropPageAndShowViewModel<TViewModel>(object parameterValuesObject)
where TViewModel : BasePageViewModel
{
ShowViewModel<TViewModel>(parameterValuesObject);
ChangePresentation(new DropCurrentBackStackEntryHint());
}
}
It is the CustomViewPresenter which does the backstack manipulation:
public class DropCurrentBackStackEntryHint : MvxPresentationHint
{
}
public class CustomViewPresenter : MvxWindowsViewPresenter
{
private readonly IMvxWindowsFrame _rootFrame;
public CustomViewPresenter(IMvxWindowsFrame rootFrame) : base(rootFrame)
{
_rootFrame = rootFrame;
}
protected Frame RootFrame
{
get { return (Frame) _rootFrame.UnderlyingControl; }
}
public override void ChangePresentation(MvxPresentationHint hint)
{
if (hint is DropCurrentBackStackEntryHint)
{
if (RootFrame.BackStack.Any())
{
RootFrame.BackStack.RemoveAt(RootFrame.BackStackDepth - 1);
}
}
base.ChangePresentation(hint);
}
}
I found only one reference to this COM exception in the web but was not helpful for me: https://github.com/Windows-XAML/Template10/issues/454
Update
I catches the unhandled exception in this handler:
void App_UnhandledException(object sender, UnhandledExceptionEventArgs e)
{
if (Debugger.IsAttached)
Debugger.Break();
e.Handled = true;
var message = "Error: \n\n" +
e.Message + "\n\n" +
e.Exception.HResult + "\n\n" +
e.Exception.Message + "\n\n" +
e.Exception.StackTrace;
new MessageDialog(message).ShowAsync();
}
When the exception is thrown I get this text:
The operation identifier is not valid.
The BackStack or ForwardStack cannot be changed while navigating.
-2147020579
The operation identifier is not valid. (Exception from HRESULT: 0x800710DD)
The HRESULT code does help me neither:
C:\> err 0x800710DD
# as an HRESULT: Severity: FAILURE (1), Facility: 0x7, Code 0x10dd
# for hex 0x10dd / decimal 4317 :
ERROR_INVALID_OPERATION winerror.h
# The operation identifier is not valid.
# 1 matches found for "0x800710DD"
Update 2
The exception is only raised when the app is built in Release mode. It does not occur in Debug mode. And I have to restart the device in order to effect it.
I think the problem is the way you call this. At first you call ShowViewModel and then you want to remove a page from the stack. And it sounds like in release mode it will be called at the same time, so you get this message.
public class DropCurrentBackStackEntryHint : MvxPresentationHint
{
public Type ViewModelType;
public DropCurrentBackStackEntryHint(Type viewModelType)
{
ViewModelType = viewModelType;
}
}
And at your presenter:
public override void ChangePresentation(MvxPresentationHint hint)
{
...
if (hint is DropCurrentBackStackEntryHint)
{
var dropHint = (DropCurrentBackStackEntryHint) hint;
var nativeView = Mvx.Resolve<IMvxViewsContainer>().GetViewType(dropHint.ViewModelType);
RootFrame.Navigate(nativeView, null);
// Perhaps you need here a await Task.Delay(200); here. You have to test the value
if (RootFrame.BackStack.Any() && RootFrame.BackStack.Count > 1)
{
RootFrame.BackStack.RemoveAt(RootFrame.BackStackDepth - 2);
}
}
...
}
An other solution, not so nice way: When you always want to delete the last page from stack, when you navigate to this page, you could delete the last page from the backstack in the code behind of your view.
public partial class XyzView
{
...
protected override void OnNavigatedTo(NavigationEventArgs e)
{
base.OnNavigatedTo(e);
if(Frame.BackStack.Any() && Frame.BackStack.Count > 1)
Frame.BackStack.RemoveAt(Frame.BackStackDepth - 2);
}
...
}
User contributions licensed under CC BY-SA 3.0