5

我正在尝试做一些可以说是个坏主意的事情,但我认为这仍然是可能的。我正在尝试覆盖 WP8 如何处理后退按钮并自己实现它。我推测如果我:

计划

  1. 只在整个应用程序中创建一个“框架”和“页面”
  2. PhoneApplicationPage.BackKeyPress除非他们即将退出应用程序,否则请始终处理好自己。

复制品

这是一个崩溃的示例项目

编码

..那么它应该工作。然而,我的尝试被 Windows Phone 挫败了。这是代码

// This basically happens on PhoneApplicationService.OnLaunched
_viewModelChanged.StartWith(ViewModel).Where(x => x != null).Subscribe(vm => {
    var page = default(IViewFor);
    var frame = RootVisual as PhoneApplicationFrame;

    // Find the initial PhoneApplicationPage for the app
    page = RxApp.GetService<IViewFor>("InitialPage");

    // Depending on how we're being signalled (i.e. if this is cold start 
    // vs. resume), we need to create the PhoneApplicationFrame ourselves
    if (frame == null) {
        frame = new PhoneApplicationFrame() {
            Content = page,
        };
    }

    page.ViewModel = vm;
    var pg = page as PhoneApplicationPage;
    if (pg != null) {
        pg.BackKeyPress += (o, e) => {
            if (ViewModel.Router.NavigationStack.Count <= 1 ||
                ViewModel.Router.NavigateBack.CanExecute(null)) {
                return;
            }

            e.Cancel = true;
            ViewModel.Router.NavigateBack.Execute(null);
        };
    }

    // Finally, set Application.RootVisual
    RootVisual = frame;
});

悲伤

这很好用,直到此代码执行后,框架排队的 DispatcherItem 使应用程序崩溃

System.NullReferenceException occurred
Message: A first chance exception of type 'System.NullReferenceException' occurred in Microsoft.Phone.ni.dll
Microsoft.Phone.ni.dll!Microsoft.Phone.Controls.PhoneApplicationPage.InternalOnNavigatedFrom(System.Windows.Navigation.NavigationEventArgs e)   Unknown
Microsoft.Phone.ni.dll!Microsoft.Phone.Controls.PhoneApplicationPage.Microsoft.Phone.Controls.IPhoneApplicationPage.InternalOnNavigatedFromX(System.Windows.Navigation.NavigationEventArgs e)   Unknown
Microsoft.Phone.ni.dll!System.Windows.Navigation.NavigationService.RaiseNavigated(object content, System.Uri uri, System.Windows.Navigation.NavigationMode mode, bool isNavigationInitiator, Microsoft.Phone.Controls.IPhoneApplicationPage existingContentPage, Microsoft.Phone.Controls.IPhoneApplicationPage newContentPage) Unknown
Microsoft.Phone.ni.dll!System.Windows.Navigation.NavigationService.CompleteNavigation(System.Windows.DependencyObject content, System.Windows.Navigation.NavigationMode mode)   Unknown
Microsoft.Phone.ni.dll!System.Windows.Navigation.NavigationService.ContentLoader_BeginLoad_Callback(System.IAsyncResult result) Unknown
Microsoft.Phone.ni.dll!System.Windows.Navigation.PageResourceContentLoader.BeginLoad_OnUIThread(System.AsyncCallback userCallback, System.Windows.Navigation.PageResourceContentLoader.PageResourceContentLoaderAsyncResult result) Unknown
Microsoft.Phone.ni.dll!System.Windows.Navigation.PageResourceContentLoader.BeginLoad.AnonymousMethod__0(object args)    Unknown
[Native to Managed Transition]  
mscorlib.ni.dll!System.Delegate.DynamicInvokeImpl(object[] args)    Unknown
System.Windows.ni.dll!System.Windows.Threading.DispatcherOperation.Invoke() Unknown
System.Windows.ni.dll!System.Windows.Threading.Dispatcher.Dispatch(System.Windows.Threading.DispatcherPriority priority)    Unknown
System.Windows.ni.dll!System.Windows.Threading.Dispatcher.OnInvoke(object context)  Unknown
System.Windows.ni.dll!System.Windows.Hosting.CallbackCookie.Invoke(object[] args)   Unknown
System.Windows.RuntimeHost.ni.dll!System.Windows.RuntimeHost.ManagedHost.InvokeDelegate(System.IntPtr pHandle, int nParamCount, System.Windows.Hosting.NativeMethods.ScriptParam* pParams, System.Windows.Hosting.NativeMethods.ScriptParam* pResult)   Unknown
4

3 回答 3

5

所以,我已经解决了这个问题——我的代码有问题,因为我没有理解 WP8 是如何工作的 :) 这就是我现在所理解的,这也可能是错误的,但我还是会写

您的 WP8 应用程序是如何初始化的:

  1. 操作系统通过重新水化 App.xaml.cs 创建您的 App 类
  2. 这意味着,您的构造函数开始运行,作为其中的一部分,您创建了一个PhoneApplicationFrame
  3. 创建 aPhoneApplicationFrame似乎PhoneApplicationService设置了一个全局静态变量(在 App.xaml 中创建时会发生同样的事情,它设置了PhoneApplicationService.Current)。
  4. NavigationService然后尝试通过资源字符串(即'/MainPage.xaml')重新创建 XAML 视图。要么它会重新创建以前被墓碑化的那个,或者如果没有,它会默认为你的 WMAppManifest 中的那个(这是我不明白的部分)。
  5. PhoneApplicationFrame.Navigated由 NavigationService 调用 - 这是您可以实际开始做的事情,包括最重要的设置 Application.RootVisual,这将发送 Loading... 屏幕
  6. PhoneApplicationService.Launched或者PhoneApplicationService.Activated最终触发,一旦基本上一切都设置好了,这取决于您的应用程序是如何被唤醒的。
于 2013-02-10T23:32:55.770 回答
4

发现问题。嗯,冰山一角。

InternalOnNavigatedFrom 方法的代码是:

internal override void InternalOnNavigatedFrom(NavigationEventArgs e)
{
    PhoneApplicationPage content = e.Content as PhoneApplicationPage;
    string str = ((content == null) || (content.Title == null)) ? string.Empty : content.Title;
    PerfUtil.BeginLogMarker(MarkerEvents.TH_ONNAVIGATEDFROM_PAGE, string.Format("{0},{1},{2}", (base.Title == null) ? "" : base.Title, e.NavigationMode, str));
    this.OnNavigatedFrom(e);
    PerfUtil.EndLogMarker(MarkerEvents.TH_ONNAVIGATEDFROM_PAGE, string.Format("{0},{1},{2}", (base.Title == null) ? "" : base.Title, e.NavigationMode, str));
    DeviceStatus.KeyboardDeployedChanged -= new EventHandler(this.OnKeyboardDeployedChanged);
    Task rootTask = ApplicationHost.Current.RootTask;
    rootTask.OnVisibleRegionChange = (ITask.VisibleRegionChanged) Delegate.Remove(rootTask.OnVisibleRegionChange, new ITask.VisibleRegionChanged(this.OnVisibleRegionChange));
    Task task2 = ApplicationHost.Current.RootTask;
    task2.OnSipVisibilityChange = (ITask.SipVisibilityChange) Delegate.Remove(task2.OnSipVisibilityChange, new ITask.SipVisibilityChange(this.OnSipVisibilityChange));
    this._lastSipHeight = 0.0;
    this._dictionary = null;
}

经过一番调试,我得出的结论是两者都不eApplication.Current.RootTask空。挠头后,我查看了KeyboardDeployedChanged事件处理程序的代码:

public static  event EventHandler KeyboardDeployedChanged
{
    [SecuritySafeCritical] add
    {
        if (KeyboardDeployedSubscription == null)
        {
            KeyboardDeployedSubscription = new SubscriptionHandler(DeviceTypes.KeyBoard);
        }
        KeyboardDeployedSubscription.Changed += value;
    }
    [SecuritySafeCritical] remove
    {
        KeyboardDeployedSubscription.Changed -= value;
    }
}

这段代码写得不好。如果在remove, 之前调用处理程序的部分addKeyboardDeployedSubscription则将为 null 并且将引发异常。App为了测试我的理论,我在的构造函数中订阅了事件:

    public App()
    {
        // Global handler for uncaught exceptions.
        UnhandledException += Application_UnhandledException;

        DeviceStatus.KeyboardDeployedChanged += (sender, e) => { };

果然,异常消失了。现在,为了理解为什么您的代码会触发此问题,我回溯到框架的哪一部分应该订阅该事件。唯一的候选者是InternalOnNavigatedTo方法。

因此,您的问题是OnNavigatedFrom即使OnNavigatedTo从未被调用过,也会被调用。

于 2013-02-10T00:31:56.800 回答
1

由于您对 Windows Phone 的内置自动导航到 WMAppManifest.xml 中定义的页面感到困惑,因此我尝试删除自动导航,它基本上可以正常工作(没有例外)。

我刚换

<DefaultTask Name="_default" NavigationPage="MainPage.xaml" />

<DefaultTask Name="_default" />

不确定这是否能解决您的问题,但至少不会再崩溃了。

于 2013-02-10T05:42:14.853 回答