2012-11-09 21 views
5

का उपयोग कर WinRT में एक मोडल संदेशबॉक्स कैसे बनाएं, इस समय मैं एक क्रॉस-प्लेटफ़ॉर्म सी ++ एसडीके पर काम कर रहा हूं और मुझे अपने जोरदार हैंडलर को WinRT पर पोर्ट करना होगा। प्रक्रिया का एक हिस्सा एक संदेश बॉक्स प्रदर्शित करना है, उपयोगकर्ता इनपुट के लिए प्रतीक्षा करें और जब उपयोगकर्ता "डीबग" चुनता है तो ब्रेकपॉइंट ट्रिगर करें।देशी सी ++

मुझे पहले से ही एक संदेश बॉक्स दिखाई देने के लिए मिला है, लेकिन मुझे संदेश बॉक्स को के बिना निष्पादन के वर्तमान बिंदु को छोड़ने के लिए प्रतीक्षा करने का कोई तरीका नहीं मिल रहा है।

यहां मेरा कोड अभी तक है।

// Create the message dialog factory 

Microsoft::WRL::ComPtr<ABI::Windows::UI::Popups::IMessageDialogFactory> messageDialogFactory; 
Microsoft::WRL::Wrappers::HStringReference messageDialogFactoryId(RuntimeClass_Windows_UI_Popups_MessageDialog); 

Windows::Foundation::GetActivationFactory(messageDialogFactoryId.Get(), messageDialogFactory.GetAddressOf()); 

// Setup the used strings 

Microsoft::WRL::Wrappers::HString message; 
Microsoft::WRL::Wrappers::HString title; 
Microsoft::WRL::Wrappers::HString labelDebug; 
Microsoft::WRL::Wrappers::HString labelIgnore; 
Microsoft::WRL::Wrappers::HString labelExit; 

message.Set(L"Test"); 
title.Set(L"Assertion triggered"); 
labelDebug.Set(L"Debug"); 
labelIgnore.Set(L"Ignore"); 
labelExit.Set(L"Exit"); 

// Create the dialog object 

Microsoft::WRL::ComPtr<ABI::Windows::UI::Popups::IMessageDialog> messageDialog; 
Microsoft::WRL::ComPtr<ABI::Windows::Foundation::Collections::IVector<ABI::Windows::UI::Popups::IUICommand*>> messageDialogCommands; 

messageDialogFactory->CreateWithTitle(message.Get(), title.Get(), messageDialog.GetAddressOf()); 
messageDialog->get_Commands(messageDialogCommands.GetAddressOf()); 

// Attach commands 

Microsoft::WRL::ComPtr<ABI::Windows::UI::Popups::IUICommandFactory> commandFactory; 
Microsoft::WRL::Wrappers::HStringReference commandFactoryId(RuntimeClass_Windows_UI_Popups_UICommand); 

Windows::Foundation::GetActivationFactory(commandFactoryId.Get(), commandFactory.GetAddressOf()); 

CInvokeHandler commandListener; 
commandFactory->CreateWithHandler(labelDebug.Get(), &commandListener, commandListener.m_DebugCmd.GetAddressOf()); 
commandFactory->CreateWithHandler(labelIgnore.Get(), &commandListener, commandListener.m_IgnoreCmd.GetAddressOf()); 
commandFactory->CreateWithHandler(labelExit.Get(), &commandListener, commandListener.m_ExitCmd.GetAddressOf()); 

messageDialogCommands->Append(commandListener.m_DebugCmd.Get()); 
messageDialogCommands->Append(commandListener.m_IgnoreCmd.Get()); 
messageDialogCommands->Append(commandListener.m_ExitCmd.Get()); 

// Show dialog 

Microsoft::WRL::ComPtr<ABI::Windows::Foundation::IAsyncOperation<ABI::Windows::UI::Popups::IUICommand*>> showOperation; 
messageDialog->ShowAsync(showOperation.GetAddressOf()); 

// ... and wait for the user to choose ...? 

और अब मैं यहां फंस गया हूं। यदि मैं कॉलबैक को ट्रिगर करने के लिए बस स्पिन-प्रतीक्षा करता हूं तो मैं अंतहीन पाश में प्रवेश कर रहा हूं और संदेश बॉक्स बिल्कुल दिखाई नहीं देता है (कम से कम जब मैं यूआई-थ्रेड से कॉल कर रहा हूं)। अगर मैं निष्पादन जारी रखता हूं तो मैं सही स्थिति पर ब्रेकपॉइंट ट्रिगर करने की संभावना खो रहा हूं।

तो मैं जो खोज रहा हूं वह रेड्रा को मजबूर करने के लिए या एसिंक कॉल को समाप्त करने के लिए "व्यस्त-प्रतीक्षा" करने का कोई तरीका है (sth। जैसे "मैसाडेडियलॉग-> शोएसिंक()" का इंतजार करें)। मुझे पता है कि मैं प्रबंधित-सी ++ का उपयोग कर सकता हूं, लेकिन मैं इसे टालना चाहता हूं :)

उत्तर

2

जब आप पॉपअप दिखाने के लिए ShowAsync() पर कॉल करते हैं, तो कार्य UI थ्रेड पर निष्पादन के लिए निर्धारित होता है। इस कार्य को चलाने के लिए, यूआई थ्रेड इसे निष्पादित करने के लिए स्वतंत्र होना चाहिए (यानी, यह अन्य कोड निष्पादित नहीं कर सकता है)। यदि आपका कोड UI थ्रेड पर निष्पादित हो रहा है और आप ShowAsync() पर कॉल करते हैं, तो आप ShowAsync() पूर्ण होने तक अवरुद्ध करते हैं, आपका एप्लिकेशन डेडलॉक होगा: पॉपअप दिखाने का कार्य तब तक प्रतीक्षा करना चाहिए जब तक कि आपका कोड यूआई थ्रेड पर चलने से रोक न जाए, लेकिन आपका कोड नहीं रुक जाएगा काम पूरा होने तक चल रहा है।

यदि आप किसी घटना के लिए या एसिंक्रोनस ऑपरेशन को पूरा करने के लिए यूआई थ्रेड पर इंतजार करना चाहते हैं, तो आपको सिंक्रनाइज़ेशन फ़ंक्शंस में से एक को कॉल करने की आवश्यकता है जो कतार को पंप करता है ताकि आप UI थ्रेड को अवरुद्ध न करें। उदाहरण के लिए, the code in the Hilo project that allows synchronization of an asynchronous operation.

दुर्भाग्य से, यह अभी भी आपकी सहायता नहीं करता है, क्योंकि Windows Store ऐप UI Application Single-Threaded Apartment (ASTA) में चलता है, जो पुनर्वित्त को प्रतिबंधित करता है। यह एक अच्छी बात है, क्योंकि अप्रत्याशित COM पुनर्वित्त बहुत भयानक कीड़े के सबसे भयानक कारणों का कारण है। मुझे नहीं लगता कि आपका फ़ंक्शन इंतजार करते समय "पॉपअप दिखाएं" कार्य चलाने का कोई तरीका है।

हालांकि, अगर यह केवल डिबगिंग के लिए है, तो आप साधारण संदेश बॉक्स दिखाने के लिए बस MessageBox पर कॉल कर सकते हैं। यह डेस्कटॉप पर दिखाई देगा, लेकिन आपका प्रोग्राम निरंतर निष्पादन से पहले कॉल को पूरा करने के लिए निश्चित रूप से प्रतीक्षा करेगा। आपका ऐप स्टोर के प्रमाणीकरण को MessageBox पर कॉल के साथ पास नहीं करेगा, लेकिन फिर, डीबग कोड के लिए, इसे ठीक काम करना चाहिए।

MessageBox की घोषणा #ifdef 'विंडोज स्टोर ऐप बनाने के दौरान डिफ़ॉल्ट रूप से संपादित करें, लेकिन आप स्वयं को फ़ंक्शन घोषित कर सकते हैं। मैंने एक लेख लिखा, "'printf' debugging in Metro style apps" जो बताता है कि यह कैसे करें।


अंत में, एक त्वरित स्पष्टीकरण: विंडोज रनटाइम के लिए "प्रबंधित सी ++" नहीं है। सी ++/सीएक्स भाषा एक्सटेंशन सिंटैक्टिक रूप से सी ++/सीएलआई के समान हैं, जो .NET Framework और CLI को लक्षित करता है, लेकिन वे अर्थात् अलग हैं। सी ++/सीएक्स का उपयोग करते समय, कोई प्रबंधित कोड नहीं है और सीएलआर रनटाइम पर लोड नहीं किया जाएगा। कंपाइलर सी ++/सीएक्स कोड को समकक्ष सी ++ कोड में बदल देता है, फिर उस कोड को संकलित करता है। यह सब 100% मूल है।

+0

विस्तृत उत्तर के लिए धन्यवाद। मुझे लगता है कि यह मुझे कुछ देर के लिए व्यस्त रखेगा :) – mmpause

0

आखिरकार मैंने जो किया उसके तुरंत बाद (जेम्स के जवाब के लिए धन्यवाद)।

यदि यूआई थ्रेड से एक जोर दिया जाता है (और ऐप एसटीए में चलता है) तो मैं बस ब्रेक करता हूं और संदेश को डिबग आउट में डाल देता हूं। मेट्रो एप्लिकेशन से डेस्कटॉप विंडो को ट्रिगर करने के लिए मुझे बस गलत लग रहा था। यदि एक गैर-यूआई थ्रेड से कोई जोर ट्रिगर किया गया है, तो "मोडल" बॉक्स पूरी तरह से काम करता है।

#include <ppltasks.h> 
using namespace concurrency; 

// ... 

auto UIDispatcher = Windows::ApplicationModel::Core::CoreApplication::MainView->CoreWindow->Dispatcher; 

try 
{ 
    auto uiTask = UIDispatcher->RunAsync(CoreDispatcherPriority::Normal, 
     ref new DispatchedHandler([&messagePopup, cmds, &result]() 
    { 
     try 
     { 
      create_task(messagePopup->ShowAsync()).then([cmds, &result](IUICommand^ selected) { 
       // result is changed depending on which command was selected 
      }); 
     } 
     catch (...) 
     { 
     } 
    })); 

    // Wait for the user to click 

    create_task(uiTask).wait(); 

    // Sleep until result has been changed 
} 
catch (invalid_operation) 
{    
    // STA, debugout & break 
} 

// test on result, etc. 

मैं अगर है कि वास्तव में सबसे अच्छा तरीका यह करने के लिए पता नहीं है, लेकिन यह काम करता है :)

आप जब कहा जाता है अन्यथा यह एक COM अपवाद फेंक देंगे, यूआई धागा करने के लिए ShowAsync प्रेषण करने के लिए की जरूरत है गैर-यूआई थ्रेड से।

मैंने पहले create_task() का उपयोग किया। तब() क्योंकि मैं आलसी ^^ हूं और उपयोगकर्ता इंटरैक्शन पर जांच कर रहा हूं।
एसटीए से बुलाए जाने पर create_task (uiTask) .wait() एक अमान्य ऑपरेशन फेंक देगा (इसलिए मुझे लगता है कि एमटीए ठीक काम करेगा)।
उस स्थिति में, प्रेषित ShowAsync भी एक COM अपवाद फेंक कर असफल हो जाएगा, इसलिए कुछ भी नहीं दिखाया गया है। आखिर में बॉक्स में ट्रिगर होने के लिए बस व्यस्त रहें।