2012-09-24 2 views
1

문제 : 비동기 적으로 검색된 수신 데이터를 렌더링하려고 할 때 충돌이 발생합니다.Metro C++ 비동기 프로그래밍 및 UI 업데이트. 내 기술?

앱이 시작되고 XAML을 사용하여 일부 대화 상자가 표시됩니다. 사용자가 데이터를 채우고 로그인 버튼을 클릭하면 XAML 클래스는 HTTP 항목을 (IXMLHTTPRequest2를 사용하여 비동기 적으로) 수행하는 작업자 클래스의 인스턴스에 있습니다. 응용 프로그램이 웹 서버에 성공적으로 로그인하면 .then() 블록이 실행되고 기본 xaml 클래스에 대한 콜백을 만들어 일부 자산 렌더링을 수행합니다.

비록 내가이 접근법 (순수 가상 클래스와 콜백)을 사용하여 내 UI를 업데이트 할 수 없다고 생각하게하는 위임자 (주 XAML 클래스)에서 항상 충돌이 발생합니다. 비동기 호출의 부산물 인 잘못된 스레드에서 불법적으로 뭔가를하려고 실수로 노력하고 있다고 생각합니다.

기본 XAML 클래스에 UI를 업데이트 할 때가되었음을 알리는 것이 더 좋거나 다른 방법이 있습니까? 나는 NotificationCenter를 사용할 수있는 IOS 세계에서 왔습니다. http://msdn.microsoft.com/en-us/library/windows/apps/hh755798.aspx

당신은 내가 내 자신의 콜백 대신이 방법을 사용하면 더 이상 충돌하지 것이라고 생각하십니까 :

는 지금, 나는 마이크로 소프트는 여기에 일의 그것의 자신의 대리자 형식을 가지고 보았다?

더 많은 설명이 필요하거나 그렇지 않은 경우 알려 주시기 바랍니다. 공용 인터페이스 클래스 ISmileServiceEvents { 공개 : 여기

코드의 JIST입니다 // 필요한 방법 가상 무효에 updateUI (BOOL isValid) 추상; };

// In main XAML.cpp which inherits from an ISmileServiceEvents 
void buttonClick(...){ 
    _myUser->LoginAndGetAssets(txtEmail->Text, txtPass->Password); 
} 
void UpdateUI(String^ data) // implements ISmileServiceEvents 
{ 
    // This is where I would render my assets if I could. 
    // Cannot legally do much here. Always crashes. 
    // Follow the rest of the code to get here. 
} 

// In MyUser.cpp 
void LoginAndGetAssets(String^ email, String^ password){ 
    Uri^ uri = ref new URI(MY_SERVER + "login.json"); 
    String^ inJSON = "some json input data here"; // serialized email and password with other data 

    // make the HTTP request to login, then notify XAML that it has data to render. 
    _myService->HTTPPostAsync(uri, json).then([](String^ outputJson){ 
     String^ assets = MyParser::Parse(outputJSON); 
     // The Login has returned and we have our json output data 
     if(_delegate) 
     { 
     _delegate->UpdateUI(assets); 
     } 
    }); 
} 

// In MyService.cpp 
task<String^> MyService::HTTPPostAsync(Uri^ uri, String^ json) 
{ 
    return _httpRequest.PostAsync(uri, 
     json->Data(), 
     _cancellationTokenSource.get_token()).then([this](task<std::wstring> response) 
    { 
     try 
     { 
      if(_httpRequest.GetStatusCode() != 200) SM_LOG_WARNING("Status code=", _httpRequest.GetStatusCode()); 
       String^ j = ref new String(response.get().c_str()); 
       return j; 
     } 
     catch (Exception^ ex) .......; 
    return ref new String(L""); 
    }, task_continuation_context::use_current()); 
} 

편집 : BTW, 나는 UI를 업데이트 갈 때 내가 오류는 다음과 같습니다 ". 잘못된 매개 변수 치명적인 유효하지 않은 매개 변수를 고려 함수에 전달했다" 난 그냥 내 콜백에서 실행하려고이 경우 그것은 잘못된 상황에서 UI 스레드를 업데이트 표시

txtBox->Text = data; 

답변

0

입니다. task_continuation_context::use_arbitrary()을 사용하여 UI를 업데이트 할 수 있습니다. this document의 "실행 스레드 제어"예제 (마샬링에 대한 설명은 맨 아래에 있음)를 참조하십시오.

+0

감사합니다. 나는 끝까지 읽었고 당신이 제안한 것과 모순되는 말을합니다. 기사 출처 : " 사용 동시성 :: task_continuation_context :: use_arbitrary 계속 백그라운드 스레드에서 실행되도록 지정하려면 사용 동시성 :: task_continuation_context :: use_current 계속이 작업라는 스레드에서 실행되도록 지정합니다. : : then. " – VaporwareWolf

+0

어느 쪽이든, 나는 둘 다 임의()로 변경하고 use_current()를 제거하려고 시도했다. 어느 누구도 문제를 해결하는 데 도움이되지 않았습니다. – VaporwareWolf

0

그래서 람다 함수 뒤에 컨텍스트를 지정하지 않으면 계속 사용하면 기본적으로 use_arbitrary()가 사용됩니다. 이것은 내가 MS 비디오에서 배운 것과 모순된다.

GUI와 관련이있는 모든 .then 블록에 use_currrent()를 추가하면 오류가 사라지고 모든 것이 제대로 렌더링 될 수 있습니다.

내 GUI는 일부 작업을 생성하고 비동기 작업을 수행하는 HTTP 클래스를 호출하는 서비스를 호출합니다. 다시 HTTP 클래스에서 use_arbitrary()를 사용하여 보조 스레드에서 실행할 수 있습니다. 이것은 잘 작동합니다. GUI와 관련이있는 경우에는 use_current()를 사용해야합니다.

내 대답은 이제 원래 코드를 보면 이미 use_current()가 있다는 것을 알 수 있습니다. 사실이지만, 예제의 단순화를 위해 줄 바꾸기 기능을 생략했습니다. 그것은 어디에서 use_current()를 추가해야하는지입니다.

+0

어떤 비디오에서 연속은 원래 스레드로 다시 정렬 될 것이라고 말했습니까? –

+0

여기 비디오가 있습니다. 실제로 꽤 좋습니다. http://channel9.msdn.com/Events/Windows-Camp/Developing-Windows-8-Metro-style-apps-in-Cpp/Async-made-simple-with-Cpp-PPL – VaporwareWolf