2012-11-01 7 views
0

나는 재산이 ViewModelView에 다음 코드를 발생 때async 및 await을 사용하여 개별 UI 컨트롤 대신 전체 응용 프로그램을 응답으로 만드는 방법은 무엇입니까?

응답 응용 프로그램을 만들기 위해 asyncawait 키워드를 사용하고 있습니다.

보기 : 버튼 클릭 이벤트

private async void button1_Click(object sender, RoutedEventArgs e) 
    { 
     button1.IsEnabled = false; 

     // Property Change 
     _viewModel.Words = await Task.Factory.StartNew(() => File.ReadAllLines("Words.txt").ToList()); // takes time to read about 3 - 4 seconds 

     switch (_viewModel.RadioButtonWordOrderSelection) 
     { 
      case MainWindowViewModel.RadioButtonWordOrderSelections.NormalOrder: 
       break; 

      case MainWindowViewModel.RadioButtonWordOrderSelections.ReverseOrder: 
       await Task.Factory.StartNew(() => 
               { 
                var words = _viewModel.Words.ToList(); 
                words.Reverse(); 
                // Property Change 
                _viewModel.Words = words; 
               }); 
       break; 

      case MainWindowViewModel.RadioButtonWordOrderSelections.Shuffle: 
       await Task.Factory.StartNew(() => 
               { 
                // Property Change 
                _viewModel.Words = _viewModel.Words.Shuffle().ToList(); 
               }); 
       break; 
     } 

     await Task.Factory.StartNew(() => DownloadSomething(_viewModel.Words)); // takes time to read about 30 - 40 seconds 

     button1.IsEnabled = true; 
    } 

_viewModel.ProgressView

보기에 업데이트되는 : 개인 방법은 30 소요 -

private void DownloadSomething(IEnumerable<string> words) 
    { 
     // Property Change 
     _viewModel.Progress = 0; 

     foreach (var word in words) 
     { 
      // Property Change 
      _viewModel.Word = word; 
      try 
      { 
       // Some code WebClient download code here 
      } 
      catch (Exception e) 
      { 
       //Trace.WriteLine(e.Message); 
      } 

      // Property Change 
      _viewModel.Progress++; 
     } 
    } 

VIEW를 완료하려면 40 초 : 소품 erty 변경 이벤트

void _viewModel_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e) 
    { 
     try 
     { 
      switch(e.PropertyName) 
      { 
       case "Progress": 
        // Since its a different Thread 
        // http://msdn.microsoft.com/en-us/magazine/cc163328.aspx 
        // Sets the Value on a ProgressBar Control. 
        // This will work as its using the dispatcher 

        // The following works 
        //Dispatcher.Invoke(
        // DispatcherPriority.Normal, 
        // new Action<double>(SetProgressValue), 
        // _viewModel.Progress); 

        // from http://stackoverflow.com/questions/2982498/wpf-dispatcher-the-calling-thread-cannot-access-this-object-because-a-differen 
        progress1.Dispatcher.Invoke(
         DispatcherPriority.Normal, 
         new Action(() => 
         { 
          progress1.Value = _viewModel.Progress; 
         }) 
        ); 

        // This will throw an exception 
        // (it's on the wrong thread) 
        //progress1.Value = _viewModel.Progress; 
        break; 

       case "Words": 
        // Since its a different Thread 
        // http://msdn.microsoft.com/en-us/magazine/cc163328.aspx 
        // Sets the Max Value on a ProgressBar Control. 
        // This will work as its using the dispatcher 

        // The following Works 
        //Dispatcher.Invoke(
        // DispatcherPriority.Normal, 
        // new Action<double>(SetProgressMaxValue), 
        // _viewModel.Words.Count); 

        // from http://stackoverflow.com/questions/2982498/wpf-dispatcher-the-calling-thread-cannot-access-this-object-because-a-differen 
        progress1.Dispatcher.Invoke(
         DispatcherPriority.Normal, 
         new Action(() => 
         { 
          progress1.Maximum = _viewModel.Words.Count; 
         }) 
        ); 

        // This will throw an exception 
        // (it's on the wrong thread) 
        //progress1.Maximum = _viewModel.Words.Count; 
        break; 

       case "Word": 
        // Since its a different Thread 
        // http://msdn.microsoft.com/en-us/magazine/cc163328.aspx 
        // Sets the Contant on a Label Control. 
        // This will work as its using the dispatcher 

        // The following Works 
        //Dispatcher.Invoke(
        // DispatcherPriority.Normal, 
        // new Action<string>(SetLastWordValue), 
        // _viewModel.Word); 

        // from http://stackoverflow.com/questions/2982498/wpf-dispatcher-the-calling-thread-cannot-access-this-object-because-a-differen 
        labelLastWord.Dispatcher.Invoke(
         DispatcherPriority.Normal, 
         new Action(() => 
         { 
          labelLastWord.Content = _viewModel.Word; 
         }) 
        ); 

        // This will throw an exception 
        // (it's on the wrong thread) 
        //labelLastWord.Content = _viewModel.Word; 
        break; 

       case "RadioButtonWordOrderSelection": 
        break; 

       default: 
        throw new NotImplementedException("[Not implemented for 'Property Name': " + e.PropertyName + "]"); 
      } 
     } 
     catch(Exception ex) 
     { 
      MessageBox.Show(ex.Message + "\n" + ex.StackTrace); 
     } 
    } 

ProgressBar1의 및 labelLastWord 완벽하게 UI를 업데이트를 취급! 그래도 progressBar1 및 labelLastWord가 나머지 UI를 업데이트 할 때 문제가 발생합니다. 고정되어 있습니다.

해결 방법이 있습니까?

대단히 감사합니다!

+0

Wpf에서는 코드가 아닌 명령을 사용해야합니다. 그런 다음 명령 내에서 쉽게 비동기/대기 할 수 있습니다. –

+0

편집 제목에 대해서는 [제목에 제목을 넣어야하는 질문] (http://meta.stackexchange.com/questions/19190/should-questions-include-tags-in-their-titles)을 참조하십시오. –

+0

@JordanKaye는 명령으로 시작하는 것이 나에게 좋은 장소라고 제안 할 수 있습니까? 귀하의 회신에 감사드립니다! –

답변

1

Task-based Async Programming document의 가이드 라인을 따르는 것이 좋습니다. 이것은 단지 StartNew을 통해 스레드 풀로 작업을 중단하는 것보다 훨씬 낫습니다. 의 경우에 CPU 바운드 작업이있는 경우 Task.Run을 사용할 수 있지만 그 밖의 모든 작업에는 기존 async -ready 끝점을 사용하십시오.

또한 전체 VM을 UI 컨텍스트에있는 것으로 취급하는 것이 유용하다는 것을 알았습니다. 따라서 PropertyChanged은 항상 UI 컨텍스트에서 발생합니다. 데이터 바인딩은 특히 이것에 달려 있습니다.

private async Task<List<string>> ReadAllLinesAsync(string file) 
{ 
    var ret = new List<string>(); 
    using (var reader = new StreamReader(file)) 
    { 
    string str = await reader.ReadLineAsync(); 
    while (str != null) 
    { 
     ret.Add(str); 
     str = await reader.ReadLineAsync(); 
    } 
    } 
    return ret; 
} 

private async void button1_Click(object sender, RoutedEventArgs e) 
{ 
    button1.IsEnabled = false; 

    _viewModel.Words = await ReadAllLinesAsync("Words.txt"); 

    List<string> words; 
    switch (_viewModel.RadioButtonWordOrderSelection) 
    { 
    case MainWindowViewModel.RadioButtonWordOrderSelections.NormalOrder: 
     break; 

    case MainWindowViewModel.RadioButtonWordOrderSelections.ReverseOrder: 
     await Task.Run(() => 
     { 
     words = _viewModel.Words.ToList(); 
     words.Reverse(); 
     }); 
     _viewModel.Words = words; 
     break; 

    case MainWindowViewModel.RadioButtonWordOrderSelections.Shuffle: 
     await Task.Run(() => 
     { 
     words = _viewModel.Words.Shuffle().ToList(); 
     }); 
     _viewModel.Words = words; 
     break; 
    } 

    await DownloadSomething(_viewModel.Words); 

    button1.IsEnabled = true; 
} 

private async Task DownloadSomething(IEnumerable<string> words) 
{ 
    _viewModel.Progress = 0; 

    foreach (var word in words) 
    { 
    _viewModel.Word = word; 
    try 
    { 
     await ...; // async WebClient/HttpClient code here 
    } 
    catch (Exception e) 
    { 
     //Trace.WriteLine(e.Message); 
    } 

    _viewModel.Progress++; 
    } 
} 

void _viewModel_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e) 
{ 
    try 
    { 
    switch(e.PropertyName) 
    { 
     case "Progress": 
     progress1.Value = _viewModel.Progress; 
     break; 

     case "Words": 
     progress1.Maximum = _viewModel.Words.Count; 
     break; 

     case "Word": 
     labelLastWord.Content = _viewModel.Word; 
     break; 

     case "RadioButtonWordOrderSelection": 
     break; 

     default: 
     throw new NotImplementedException("[Not implemented for 'Property Name': " + e.PropertyName + "]"); 
    } 
    } 
    catch(Exception ex) 
    { 
    MessageBox.Show(ex.Message + "\n" + ex.StackTrace); 
    } 
} 

닫기주의 사항으로 Josh Smith's MVVM book을 구입하여 자세히 읽으십시오. "View"및 "ViewModel"과 같은 용어를 사용하고 있지만 이러한 구성 요소를 사용하는 방식은 입니다. 완전히이므로 MVVM 패턴의 모든 이점을 피할 수 있습니다.