UWP - Platform::DisconnectedException 在页面之间导航时

UWP - Platform::DisconnectedException while navigating between pages

我有以下设置:MainPage xaml-view 和 SettingPage xaml-view。在 SettingPage xaml-view 中,我激活了 window 标题栏中的后退按钮,并添加了 BackRequestedEventArgs。 (此外,我有一个 DX12 xaml 页面,但它还没有涉及到导航,所以它永远不会被初始化。)

所以我的问题是:如果我单击位于 MainPage 中名为 settings 的弹出式项目,我将导航到 SettingPage。后退按钮出现在标题栏中,如果我单击它,我将返回到主页面。现在我再做一次:点击设置,导航到设置页面。现在,如果我单击后退按钮或关闭 window 应用程序崩溃并向我显示以下异常:

Platform::DisconnectedException ^ at 0x046BED80. HRESULT:0x80010108

我的问题:我该如何解决?

这是我的代码:

主页导航:

    void MainPage::MenuFlyoutItemSettings_Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e)
    {

     this->Frame->Navigate(Windows::UI::Xaml::Interop::TypeName(SettingsPage::typeid));

    }

设置页面:

 // in Constructor
Windows::UI::Core::SystemNavigationManager::GetForCurrentView()->AppViewBackButtonVisibility = Windows::UI::Core::AppViewBackButtonVisibility::Visible;
Windows::UI::Core::SystemNavigationManager::GetForCurrentView()->
    BackRequested += ref new Windows::Foundation::EventHandler<
    Windows::UI::Core::BackRequestedEventArgs^>(
        this, &SettingsPage::App_BackRequested);



void SettingsPage::App_BackRequested(
    Platform::Object^ sender,
    Windows::UI::Core::BackRequestedEventArgs^ e)
{
    Windows::UI::Xaml::Controls::Frame^ rootFrame = dynamic_cast<Windows::UI::Xaml::Controls::Frame^>(Window::Current->Content);
    if (rootFrame == nullptr)
        return;

    // Navigate back if possible, and if the event has not
    // already been handled.
    if (rootFrame->CanGoBack && e->Handled == false)
    {
        e->Handled = true;
        rootFrame->GoBack();
    }
}

此外,这两种方法都有我手动添加的 onSuspending 和 onResuming 处理程序,但它们都是空的:

//in constructor

    Application::Current->Suspending += ref new SuspendingEventHandler(this, &SettingsPage::OnSuspending);
    Application::Current->Resuming += ref new EventHandler<Object^>(this, &SettingsPage::OnResuming);


void SettingsPage::OnSuspending(Object^ sender, SuspendingEventArgs^ e) {


}

void SettingsPage::OnResuming(Object^ sender, Object^ e) {


}

注意:如果我删除整个 backbutton-code,应用程序永远不会因此异常而崩溃,所以我认为这是此代码中的一个错误。

编辑 2017-09-04:

在处理 Sunteen Wu - MSFT 下面的回答后,我意识到即使我删除了所有 backbutton-code,我在第一次进入设置页面并关闭应用程序时也会收到此异常。所以这是我目前遇到的异常情况:

我现在唯一的导航代码:

主页(在自定义设置按钮中):

this->Frame->Navigate(Windows::UI::Xaml::Interop::TypeName(SettingsPage::typeid));

设置页面(在自定义后退按钮中):

this->Frame->Navigate(Windows::UI::Xaml::Interop::TypeName(MainPage::typeid));

所以在我第一次通过按下设置按钮导航到设置页面后,只有当我关闭应用程序时才会出现所描述的异常(如果单击红色 x 或停止调试器也是如此)。虽然导航工作正常,但我可以根据需要在页面之间切换,并且在 运行 应用程序时不会出现异常。

最终答案 2017-09-06:

合并 Sunteen Wu - MSFT 的回答并删除上述内容

Application::Current->Suspending += ref new SuspendingEventHandler(this, &SettingsPage::OnSuspending);
Application::Current->Resuming += ref new EventHandler<Object^>(this, &SettingsPage::OnResuming);

处​​理程序是我的解决方案。现在没有 Disconnectedexception 并且 Back-Button-Logic 也在工作!

Platform::DisconnectedException ^ at 0x046BED80. HRESULT:0x80010108

实际上您遇到了 周期 问题。循环问题是什么以及如何解决请参考Weak references and breaking cycles (C++/CX)。您在订阅 BackRequested 事件句柄时遇到了循环问题。使用 WeakReference 你会发现问题:

WeakReference wr(this);
Windows::UI::Core::SystemNavigationManager::GetForCurrentView()->
    BackRequested += ref new Windows::Foundation::EventHandler<
    Windows::UI::Core::BackRequestedEventArgs^>([wr](
        Object^ sender, Windows::UI::Core::BackRequestedEventArgs^ e)
{
    SettingsPage^ c = wr.Resolve<SettingsPage>();
    if (c != nullptr)
    {
        Windows::UI::Xaml::Controls::Frame^ rootFrame = dynamic_cast<Windows::UI::Xaml::Controls::Frame^>(Window::Current->Content);
        if (rootFrame == nullptr)
            return;
        if (rootFrame->CanGoBack && e->Handled == false)
        {
            e->Handled = true;
            rootFrame->GoBack();
        }
    }
    else
    { 
        throw ref new DisconnectedException(); 
    }
});

从文章中可以看出,当事件处理程序抛出 DisconnectedException 时,它会导致事件从订阅者列表中删除处理程序。为了解决它,您可以在返回请求后从订阅者列表中删除事件句柄。以下代码片段显示了如何删除。

Windows::Foundation::EventRegistrationToken cookie;
SettingsPage::SettingsPage()
{
    InitializeComponent();
    ...
    cookie = Windows::UI::Core::SystemNavigationManager::GetForCurrentView()->
        BackRequested += ref new Windows::Foundation::EventHandler<
        Windows::UI::Core::BackRequestedEventArgs^>(
            this, &SettingsPage::App_BackRequested);     
}

void SettingsPage::App_BackRequested(
    Platform::Object^ sender,
    Windows::UI::Core::BackRequestedEventArgs^ e)
{
    ...
    Windows::UI::Core::SystemNavigationManager::GetForCurrentView()->
        BackRequested -= cookie;
}

此外,我建议您在 App.xaml.cpp 内订阅此活动以避免此问题。您可以在 OnLaunched 内订阅它,如下所示:

void App::OnLaunched(Windows::ApplicationModel::Activation::LaunchActivatedEventArgs^ e)
{
    auto rootFrame = dynamic_cast<Frame^>(Window::Current->Content);
    // Do not repeat app initialization when the Window already has content,
    // just ensure that the window is active
    if (rootFrame == nullptr)
    {  
     ...
    }
    else
    {
      ...
    }    
    Windows::UI::Core::SystemNavigationManager::GetForCurrentView()->
        BackRequested += ref new Windows::Foundation::EventHandler<
        Windows::UI::Core::BackRequestedEventArgs^>(
            this, &App::App_BackRequested);
}

void App::App_BackRequested(
    Platform::Object^ sender,
    Windows::UI::Core::BackRequestedEventArgs^ e)
{
     ...
}

更多细节可以参考BackButton官方样本。