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;
}

これは、2つのボタンを使用してポップアップを開いたり閉じたりする最初の1〜2回の試行でうまく機能するようです。ただし、数回試行した後、Windows.UI.Xaml.dllnullポインターを逆参照しようとすると、アプリケーションはすぐに深くクラッシュします。これをC#で再現することもできます(実質的に同じコードで)。

誰かがアイデアを持っていますか、ここで何が起こっているのですか?または、代替アプローチの提案ですか?

4

2 に答える 2

0

興味のある方:数日後、MSDNフォーラムで同じ質問をし、Microsoftの従業員から回答を得ました。

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

どうやらここでの問題は、イベントハンドラー内でProcessEventsを呼び出すことによって引き起こされるネストされたメッセージループです。これはWinRTでサポートされていないようですが、明確に定義された方法で失敗する代わりに、クラッシュが発生するか、発生する可能性があります。

残念ながら、これが私が見つけた最良かつ唯一の答えだったので、イベントハンドラー(および他の多くのコード)を別のスレッドにディスパッチすることで、問題を回避することになりました。次に、ユーザーがXAMLの「ダイアログ」ポップアップのボタンをクリック/タップしたときに通知されるイベントを待機することで、 DialogBox()/ (メインスレッドの外部)の待機動作をエミュレートできます。DialogBoxParam()

于 2013-01-11T03:53:53.770 に答える
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 に答える