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官方样本。
我有以下设置: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官方样本。