CoreDispatcher.ProcessEvents()导致间接崩溃?

时间:2012-08-30 15:22:18

标签: xaml microsoft-metro windows-runtime c++-cx

我必须移植一些遗留代码,它们使用模态对话框到Metro / WinRT(使用C ++ / CX)。因为这些对话框提供了自己的消息循环(使用DialogBoxParam()),所以调用代码将等到用户单击消息框上的按钮。

我目前正在尝试为旧的消息框类编写替代品,该类使用XAML和弹出控件。为了重现相同的行为,我必须在调用线程中等待,但也必须保持UI响应。我发现,CoreDispatcher::ProcessEvents()可以在循环中使用,以保持处理事件(是的,我知道这不是很漂亮,但我不想将所有遗留代码更改为新的线程模型)。但是我遇到了一个让我的应用程序崩溃的问题。

这是一个重现问题的最小示例(只需创建一个XAML应用并将其连接到一个按钮):

void CPPXamlTest::MainPage::Button_Click_1(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e)
{
    bool cancel = false;

    auto popup = ref new Popup();
    auto button = ref new Button();
    button->Content = "Boom";
    auto token = (button->Click += ref new RoutedEventHandler([&cancel] (Object ^, RoutedEventArgs ^) { cancel = true; }));
    popup->Child = button;
    popup->IsOpen = true;

    while (!cancel)
    {
        Window::Current->Dispatcher->ProcessEvents(CoreProcessEventsOption::ProcessOneAndAllPending);
    }

    popup->IsOpen = false;
    button->Click -= token;
}

这似乎适用于使用两个按钮打开和关闭弹出窗口的前一两次尝试。但是,经过几次尝试后,应用程序将立即在Windows.UI.Xaml.dll中崩溃,同时尝试取消引用空指针。我也可以在C#中重现这一点(实际上代码相同)。

有没有人有想法,这里发生了什么?或建议采用其他方法?

2 个答案:

答案 0 :(得分:0)

如果有人有兴趣:几天后我在MSDN论坛上问了同样的问题,并得到了微软员工的回复:

http://social.msdn.microsoft.com/Forums/en-US/winappswithnativecode/thread/11fa65e7-90b7-41f5-9884-80064ec6e2d8/

显然这里的问题是在事件处理程序中调用ProcessEvents引起的嵌套消息循环。 WinRT似乎不支持这种做法,但这不会以明确定义的方式失败,而是会导致崩溃。

这是我能找到的最好和唯一的答案,所以我最终通过将事件处理程序(和许多其他代码)分派到另一个线程来解决问题。然后,我可以通过等待用户在我的XAML“对话框”弹出窗口中单击/点击按钮时发出信号的事件来模拟DialogBox() / DialogBoxParam()(主线程之外)的等待行为。

答案 1 :(得分:0)

对我来说很好的解决方法是替换以下行:

Window::Current->Dispatcher->ProcessEvents(CoreProcessEventsOption::ProcessOneAndAllPending);

使用:

auto myDispatchedHandler = ref new DispatchedHandler([&](){
   Window::Current->Dispatcher->ProcessEvents(CoreProcessEventsOption::ProcessOneAndAllPending);
}); 
dispatcher->RunAsync(CoreDispatcherPriority::Normal,myDispatchedHandler);

有关详细信息,请参阅MSDN上的this post