1

我必须将一些遗留代码移植到 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# 中重现它(使用几乎相同的代码)。

有谁知道,这里发生了什么?或者对替代方法的建议?

4

2 回答 2

0

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

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

和:

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

有关更多信息,请参阅MSDN 上的这篇文章

于 2013-10-16T15:29:30.533 回答
0

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

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

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

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

于 2013-01-11T03:53:53.770 回答