2013-08-08 3 views
1

Google 프로그램 중 하나에 대한 창 관리자를 작성하려고합니다. 각 창에서 다른 정보를 묻고 다음 창으로 이동하기 전에 해당 정보를 처리하는 일련의 창을 클라이언트에 표시해야합니다. 새 창을 동적으로 추가하거나 제거 할 수 있으므로 창 관리자가됩니다. 이렇게하기 위해 부모 창을 제공하는 메인 셸이 있습니다. 각 하위 창이 부모 창에 내용으로 삽입됩니다. 다음 버튼을 클릭하면 화면 정보를 처리 한 다음 부모에게 다음 창으로 이동할 수 있음을 알립니다. 일부 Windows에서는 처리 시간이 최대 30 초까지 걸릴 수 있으므로이 처리가 진행되는 동안 사용 중 표시기를 표시하려고합니다. 부모보기에서 Telerik RadBusyIndicator를 사용하여이를 수행하고 있습니다. 통화 중 표시기를 제대로 표시하기 위해 await/async를 사용하여 OnNext 메서드를 비동기 적으로 호출하려고합니다. OnNext 메서드가 호출되고 처리가 진행 중이지만 처리 중에 UI 스레드가 잠겨 있고 사용 표시기가 표시되지 않습니다.이 제대로 작동하지 않을 것입니다.

ShellViewModel.cs (부모 윈도우의 뷰 모델) :

protected async void NextAction() 
    { 
        //This is the property that is bound to the RadBusyIndicator to indicate if it should show or not 
     IsBusy = true; 

        //windowManager is the class that tells the child window to start processing and provides the parent window with the next view 
     bool? retVal = await windowManager.OnNext(); 

     if (retVal == true) 
     { 
      GetCurrentView(); 
     } 
     else if (retVal == null) 
     { 
      SetupApp.IsRestarting = true; 
      GetCurrentView(); 
      SetupApp.Config.RestartPoint = windowManager.CurrentViewCounter; 
      File.WriteAllText("Config.xml", SetupConfig.Serialize(SetupApp.Config)); 
      System.Diagnostics.Process.Start(Application.ResourceAssembly.Location); 
      Application.Current.Shutdown(); 
     } 

     IsBusy = false; 
    } 

    private async void GetCurrentView() 
    { 
     IsBusy = true; 

     SetupViewInit retVal = await windowManager.InitializeView(); 

     if (retVal == SetupViewInit.CloseApp) 
     { 
      RaiseCloseRequest(); 
      IsBusy = false; 
      return; 
     } 

     IsBusy = false; 

     Content = windowManager.CurrentView as FrameworkElement; 

     OnPropertyChanged("CanNext"); 
     OnPropertyChanged("CanBack"); 
     OnPropertyChanged("NextToolTip"); 

     if (windowManager.IsFinalView) 
     { 
      CancelText = "Close"; 
      SetupApp.IsComplete = true; 
     } 
    } 

SetupWindowManager.cs : 다시

public async Task<bool?> OnNext() 
    { 
        //calls into the current view model to begin processing 
     bool? retVal = CurrentViewModel.OnNext(); 

     if (retVal == true) 
      CurrentViewCounter++; 

     return retVal; 
    } 

      //Called from GetCurrentView to set the current view model and perform any initialization that view model might need 
    public async Task<SetupViewInit> InitializeView() 
    { 

     CurrentView = currentViewList[CurrentViewCounter]; 
     CurrentViewModel.FireNextAction += FireNextAction; 
     CurrentViewModel.PropertyChanged += PropertyChanged; 
     SetupViewInit retVal = CurrentViewModel.Init(); 

     if (retVal == SetupViewInit.NextScreen) 
     { 
      CurrentViewCounter++; 
      retVal = await InitializeView(); 
     } 
     else if (retVal == SetupViewInit.TypeChange) 
     { 
      SetupType = SetupApp.Config.SetupType; 
      MachineType = SetupApp.Config.MachineType; 
      GetViewList(); 
      retVal = await InitializeView(); 
     } 

     return retVal; 
    } 

의 전부를 다음과 같이 내 코드의 관련 부분은 코드가 제대로 실행되고 있습니다. 코드는 UI 스레드를 잠그고 있습니다. 어떤 차이가 있다면, .net 4.0에서 Bcl 컴파일러 구성 요소를 사용하고 있습니다. 큰 프로젝트이며 .net 4.5로 이동할 준비가되지 않았습니다.

편집 : Sethcran의 답변에 대한 내 답변이 너무 길어서 의견이 분분 할 것입니다.

아직 .Net 4.5 라이브러리를 사용하고 있지 않기 때문에 Task.Run을 사용할 수 없습니다. 하지만, Task를보고있어 .Factory.StartNew. 아래에 표시된대로 코드를 변경하고 주석에 표시된 문제가 발생했습니다.

 Task.Factory.StartNew<SetupViewInit>(new Func<SetupViewInit>(async() => 
     { 
      CurrentView = currentViewList[CurrentViewCounter]; 
      CurrentViewModel.FireNextAction += FireNextAction; 
      CurrentViewModel.PropertyChanged += PropertyChanged; 
      SetupViewInit retVal = CurrentViewModel.Init(); 

      if (retVal == SetupViewInit.NextScreen) 
      { 
       CurrentViewCounter++; 
       retVal = await InitializeView(); 
      } 
      else if (retVal == SetupViewInit.TypeChange) 
      { 
       SetupType = SetupApp.Config.SetupType; 
       MachineType = SetupApp.Config.MachineType; 
       GetViewList(); 
       retVal = await InitializeView(); 
      } 
          //On the following line, VS shows an "Unexpected return value" error 
      return retVal; 

     })); 

그래서 작업에서 반환 값을 얻으려면 어떻게해야합니까?

나는이 방법들 중 하나를 작동시키지 못하고 완전히 다른 경로로 가게되었다. 제안 해 주셔서 감사합니다. 그러나이 프로젝트에서 더 이상 그들과 어울리지 못하게 할 시간이 없습니다.

+1

당신이 OnNext' 동 기적으로 실행 '을 알리는받을 컴파일러 경고를 무시하지 마십시오. 또한,'async void'를 피하십시오. –

+0

작업에서 비동기 메서드를 호출 중이므로 작업 자체가 작업을 반환하는지 확인하십시오. 특히, Func 이 Func 일 필요가 있다고 생각합니다. > – Sethcran

답변

1

await 및 async 키워드를 사용하더라도 이후에 비동기 적으로 코드가 실행되지는 않습니다. 비동기 메서드를 호출하면 정상적으로 실행됩니다. 유일한 차이점은 결과가 Task 객체로 반환된다는 것입니다. 나는 당신의 사건에서, 명시 적으로 작업이 다른 스레드로 보내지거나 나중에 대기하도록 보지 않았으므로 처리 메소드가 반환 될 때까지이 Task 객체가 반환되지 않으며 이미 완료로 표시되었다고 생각합니다. , 따라서 귀하의 대기 키워드와 비동기 키워드는 실제로 아무 것도하지 않습니다.

return Task.Run(() => { yourLongProcessingMethodsHere }); 

이 비동기 적으로 전달 된 코드를 실행하고 동시에 명시 적 작업 개체에서 현재 스레드에서 반환을 통해 당신이 실제로 작업 내에서 비동기 적으로 실행하고자하는 코드를 포장 고려

, 현재 실행 중입니다.

즉, async/await은 명시 적으로 작업하도록 작성된 메서드에 대해서만 잘 수행 할 것이며 작업을 위해 자체 스레드를 스핀 오프하거나 이벤트를 큐에 넣을 수 있습니다 나중에 실행하여 작업 완료를 표시합니다.

비동기에 대한 자세한 내용은/await를 참조하십시오 http://msdn.microsoft.com/en-us/library/vstudio/hh191443.aspx

+0

질문을 편집하십시오. 우리는 .net 4.5를 아직 사용하지 않기 때문에 Task.Run을 사용할 수 없습니다. –

+0

Task.Factory.StartNew는 Task.Run이 추가되기 전에 작업을 시작하기위한 원래의 기본 방법과 마찬가지로 사용하기 시작한 것과 거의 같습니다. 따라서 변경 사항이 잘 수행되어야합니다. – Sethcran

+0

@DrewBurchett'Task.Run (someAction)'은'Task.Factory.StartNew (someAction, CancellationToken.None, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default); '를 입력하기위한 바로 가기입니다. [여기 있습니다 기사] (http://blogs.msdn.com/b/pfxteam/archive/2011/10/24/10229468.aspx) 자세히 설명합니다. –

관련 문제