2009-11-03 5 views
2

저는 실버 라이트에 익숙하지 않고 비동기식 파일 다운로드 만 가능하다는 사실에 매우 놀랐습니다. 글쎄, 난이 내 간단한 코드입니다 .. 단지 플래그를 설정하고 변경할 수 기다리고에 의해 을이 행동에 대응하기 위해 시도했습니다블로킹/동기 방식으로 파일을 다운로드하는 방법은 무엇입니까?

void MainPage_Loaded(object sender, RoutedEventArgs e) 
    { 
     WebClient webClient = new WebClient(); 
     webClient.DownloadProgressChanged += 
      new DownloadProgressChangedEventHandler(webClient_DownloadProgressChanged); 
     webClient.OpenReadCompleted += new OpenReadCompletedEventHandler(webClient_OpenReadCompleted); 
     webClient.OpenReadAsync(new Uri("/trunk/internal/SilverLightInterface.ashx?xxid=XXX", UriKind.Relative)); 
     while (XmlStateStream == null) { } 
     lblProgress.Content = "Done Loading"; 
    } 
    void webClient_DownloadProgressChanged(object sender, 
     DownloadProgressChangedEventArgs e) { 

     lblProgress.Content = "Downloading " + e.ProgressPercentage + "%"; 
    } 
    volatile Stream XmlStateStream = null; 
    void webClient_OpenReadCompleted(object sender, OpenReadCompletedEventArgs e) 
    { 
     if (e.Error != null) 
     { 
      lblProgress.Content = "Error: " + e.Error.Message; 
      return; 
     } 
     XmlStateStream = e.Result; 

    } 

이 실제로 때 매우 성가신 인 (동결 파이어 폭스를 일으키는 내가 개발 중에 다른 일을하고있다.) (btw, 파이어 폭스의 명성 때문에 테스트 해 보았고 파이어 폭스는 얼어 버렸지 만 복원 후 여기서 입력 한 내용을 잃지 않았다.) while(XmlStateStream==null){}은 왜 그런지 모르겠다. 얼어 붙었다. 자물쇠 또는 휘발성 (내가 이미 가지고있는 것을 제외하고)을위한 속성이 있습니까? 아니면 Silverlight 페이지 수명주기 또는 다른 부분에 있습니까?

저는 이것이 왜 작동하지 않는지에 대해 정말로 혼란 스럽습니다.

또한,이, 3.0

+0

(. 즉, 실버) 이벤트 중심의 UI에 프로그래밍 당신은 항상 대체 비동기 방법을 사용한다 :

여기에 전체 코드입니다. 동기식으로이 작업을 수행해야하는 이유는 무엇입니까? –

답변

5

대부분의 경우 실버입니다이 코드는 사용자와 웹 브라우저의 모든 상호 작용을 처리하는 UI 스레드에서 실행됩니다. 이것이 블록킹 연산을 발견하지 못하는 이유입니다. 차단 된 모든 것이 사용자가 본 것과 동일한 방식으로 UI를 정지시킬 것이기 때문입니다! 또한 UI 스레드가 네트워크 IO (일반적인 경우)를 처리하는 경우 대기중인 비동기 작업이 끝나지 않으므로 교착 상태가됩니다.

비동기 작업으로 구동되는 상태 시스템으로 코드를 다시 작성해야 할 것 같습니다.

0

DownloadFileCompleted 이벤트를 사용해야합니다.

이 삭제 :

webClient.DownloadFileCompleted += 
    new DownloadFileCompletedEventHandler(webClient_DownloadFileCompleted); 

이 :

void webClient_DownloadFileCompleted(object sender, AsyncCompletedEventHandler) { 
    lblProgress.Content = "Done Loading"; 
} 

당신이 정말로 동기 다운로드를해야하는 경우, 당신은 위해에 "설문 조사를"필요

while (XmlStateStream == null) { } 
lblProgress.Content = "Done Loading"; 

이 추가 다운로드가 거의 완료되지 않습니다. 통화 대기 루프에서 120-250ms 지연된 System.Threading.Thread.Sleep()을 호출 해보십시오.

이렇게하면 코드 낭비되는 CPU 사용을 줄일 수 있지만 UI 응답 성 문제가 해결되지 않을 수도 있습니다. 그것은 MainPage_Loaded을 호출하는 스레드가 UI 업데이트 이벤트를 호출 할 수있는 유일한 스레드인지 여부에 달려 있습니다. 그렇다면 UI는 핸들러가 반환 될 때까지 단순히 업데이트 할 수 없습니다.

+0

동기식 방식을 다운로드하지는 않습니까? 나는 OP의 실제 코드가 여기 예제보다 훨씬 더 복잡하다고 생각합니다. :/ – bdonlan

+0

그럼에도 불구하고, 그것이 OP가해야 할 일입니다. 사실 나는 다른 스레드에서 다운로드가 발생할 수 있기 때문에 동기 요청이 사실상 불가능하다고 생각합니다. 복잡성에 관계없이 이벤트 중심의 시스템이며 절차 적이며 동기식 코드를 작성하려고하면 결코 잘 작동하지 않습니다. 건 팁으로 "어떻게 발에서 스스로 쏘지?"라고 대답하는 것이 즐거울 수도 있지만 때로는 "하지 말라"는 최고의 충고입니다. –

+0

방금이 프로그램을 작성하기 시작했으나 그것을 작성하려고 시도하는 것이 "자연스러운"방법이었습니다. 좀 더 힘들어지기 때문에 더 평행 할 수 있습니다. (심지어 더!) Silverlight 프로그래밍을 조정하기 위해서 .. 나는 실버 라이트에 멀티 스레딩이 너무 많다는 것을 알지 못했다. (또는 다운로드가 UI 스레드에서 일어나기 때문에 조금 지나치다) – Earlz

2

당신이 좀 더 함께 일을 유지하기 위해 C# 3 구문을 사용할 수 있습니다 실버 라이트 것들의 비동기 자연을 얻을 필요 동안 : - 파일이 다운로드 될 때까지 차단하여

void MainPage_Loaded(object sender, RoutedEventArgs e) 
{ 
    DownloadXmlStateStream(); 
} 

void DownloadXmlStateStream() 
{ 
    WebClient webClient = new WebClient(); 

    webClient.DownloadProgressChanged += (s, e) => {  
     lblProgress.Content = "Downloading " + e.ProgressPercentage + "%"; 
    } 

    webClient.OpenReadCompleted += (s, e) => { 
     if (e.Error != null) 
     { 
      lblProgress.Content = "Error: " + e.Error.Message; 
     } 
     else 
     { 
      XmlStateStream = e.Result; 
      lblProgress.Content = "Done Loading"; 
     }   
    } 

    webClient.OpenReadAsync(new Uri("/trunk/internal/SilverLightInterface.ashx?xxid=XXX", UriKind.Relative)); 
} 
+0

익명 함수 ... 음. 잘 됐네. 네가 완전히 할 수 있다는 걸 몰랐어. – Earlz

0

, 당신이있어 Silverlight 앱의 UI 스레드를 차단할뿐만 아니라 브라우저의 UI 스레드를 차단할 수도 있습니다.

당신이 정말로하고 싶은 것은 (내가 상상 한 것) 다운로드가 완료 될 때까지 앱이 아무 것도하지 않는 것입니다.MainPage_Loaded이 줄을 추가하십시오 :

LayoutRoot.IsHitTestVisible = false; 

은 차단을 제거하는 동안 루프와 완료 메시지 (마지막 두 줄). webClient_OpenReadCompleted에서

는 추가 :

LayoutRoot.IsHitTestVisible = true; 
lblProgress.Content = "Done Loading."; 

그리고 모든 것이 내가 원하는 생각하는 방식으로 작동한다. 당신이 무거운 작업로드가있을 때

void MainPage_Loaded(object sender, RoutedEventArgs e) 
    { 
      WebClient webClient = new WebClient(); 
      webClient.DownloadProgressChanged += 
        new DownloadProgressChangedEventHandler(webClient_DownloadProgressChanged); 
      webClient.OpenReadCompleted += new OpenReadCompletedEventHandler(webClient_OpenReadCompleted); 
      webClient.OpenReadAsync(new Uri("/trunk/internal/SilverLightInterface.ashx?xxid=XXX", UriKind.Relative)); 
      LayoutRoot.IsHitTestVisible = false; 
    } 
    void webClient_DownloadProgressChanged(object sender, 
      DownloadProgressChangedEventArgs e) { 

      lblProgress.Content = "Downloading " + e.ProgressPercentage + "%"; 
    } 

    void webClient_OpenReadCompleted(object sender, OpenReadCompletedEventArgs e) 
    { 
      if (e.Error != null) 
      { 
        lblProgress.Content = "Error: " + e.Error.Message; 
        return; 
      } 
      LayoutRoot.IsHitTestVisible = true; 
      lblProgress.Content = "Done Loading."; 

    } 
관련 문제