11

MVVM Light을 사용하여 WP7 (Windows Phone 7) 응용 프로그램을 작성하고 있습니다. Model에 의해 수행 된 모든 작업을 백그라운드 스레드에서 실행하고 싶습니다. 그런 다음 작업이 완료되면 ViewModel이 데이터를 처리 할 수 ​​있도록 이벤트를 발생시킵니다.Windows Phone 7 용 백그라운드 스레드에서 함수를 실행하는 방법은 무엇입니까?

WP7 앱에서 위임을 비동기 적으로 호출 할 수 없다는 것을 이미 알아 냈습니다.

현재 ThreadPool.QueueUserWorkItem()을 사용하여 백그라운드 스레드에서 일부 코드를 실행하고 MVVM Light의 DispatcherHelper.CheckBeginInvodeOnUI()를 사용하여 데이터가로드 된 ViewModel에 신호를 보내기 위해 UI 스레드에서 이벤트를 발생 시키려고합니다. (디자인 타임보기를 표시하려고 할 때 VS2010과 Blend 4가 ​​충돌합니다).

백그라운드 스레드에 일부 코드를 실행 한 다음 WP7 앱용 UI 스레드로 다시 이벤트를 보내려면 샘플 코드가 있습니까?

미리 감사드립니다. Jeff.

편집 - 다음은 샘플 모델

public class DataModel 
{ 
    public event EventHandler<DataLoadingEventArgs> DataLoadingComplete; 
    public event EventHandler<DataLoadingErrorEventArgs> DataLoadingError; 
    List<Data> _dataCasch = new List<Data>(); 

    public void GetData() 
    { 
     ThreadPool.QueueUserWorkItem(func => 
     { 
      try 
      { 
       LoadData(); 
       if (DataLoadingComplete != null) 
       { 
        //Dispatch complete event back to the UI thread 
        DispatcherHelper.CheckBeginInvokeOnUI(() => 
        { 
         //raise event 
         DataLoadingComplete(this, new DataLoadingEventArgs(_dataCasch)); 
        }); 
       } 
      } 
      catch (Exception ex) 
      { 
       if (DataLoadingError != null) 
       { 
        //Dispatch error event back to the UI thread 
        DispatcherHelper.CheckBeginInvokeOnUI(() => 
        { 
         //raise error 
         DataLoadingError(this, new DataLoadingErrorEventArgs(ex)); 
        }); 
       } 
      } 
     }); 
    } 

    private void LoadData() 
    { 
     //Do work to load data.... 
    } 
} 

답변

16

다음은이 문제에 대한 해결책을 제시합니다.

ViewModel에서 INotifyPropertyChanged가 올바르게 구현 되었습니까? 이벤트를 파견 할 필요가 없습니다. 모델에서 "bare"키를 올린 다음 ViewModel에 RaisePropertyChanged를 전달하십시오.

그리고 네, 코드에서 일종의 싱글 톤 모델/데이터베이스가 있어야합니다. 결국, 어떤 거대한 싱글 톤이 아니라면 SQL 데이터베이스는 무엇입니까? WP7에 데이터베이스가 없으므로 싱글 톤 객체를 만드는 것을 부끄러워하지 마십시오. 나는 "데이터베이스"라고 불리는 것을 가지고있다. :)

나는 단지 내 dataloads를 스레딩 해 보았고 실제로 가장 좋은 접근법은 모델 레벨에서 INotifyPropertyChanged를 구현하는 것이다. There's no shame in this.

그래서, 여기에 내가 싱글 (Singleton) Database 객체에서 수행하는 작업으로 내 Tours "테이블"을로드하고 리턴합니다 (thread.sleep이로드에 가시적 인 시간을 가지도록주의하십시오. 보통 서브 100ms). 데이터베이스 클래스는 이제 INotifyPropertyChanged를 구현하고로드가 완료되면 이벤트를 발생시킵니다.

public ObservableCollection<Tour> Tours 
{ 
    get 
    { 
    if (_tours == null) 
    { 
     _tours = new ObservableCollection<Tour>(); 
     ThreadPool.QueueUserWorkItem(LoadTours); 
    } 
    return _tours; 
    } 
} 

private void LoadTours(object o) 
{ 
    var start = DateTime.Now; 
    //simlate lots of work 
    Thread.Sleep(5000); 
    _tours = IsoStore.Deserialize<ObservableCollection<Tour>>(ToursFilename) ?? new ObservableCollection<Tour>(); 
    Debug.WriteLine("Deserialize time: " + DateTime.Now.Subtract(start).ToString()); 
    RaisePropertyChanged("Tours"); 
} 

다음을 수행 했습니까? 백그라운드 스레드에서 Tour 목록을 비 직렬화 한 다음 propertychanged 이벤트를 발생시킵니다.

이제 ViewModel에서 TourviewModels 목록을 바인딩 할 수 있습니다. Tours 테이블이 변경되면 linq 쿼리로 선택합니다.ViewModel에서 Database 이벤트를 수신하는 것은 약간 저렴 할 것입니다. 모델에서 캡슐화하는 것이 더 좋을 수도 있지만, 우리가 필요로하지 않는 작업을하지 않겠습니까?

후크 뷰 모델의 생성자에 데이터베이스 이벤트 :

public TourViewModel() 
{ 
Database.Instance.PropertyChanged += DatabasePropertyChanged; 
} 

(! 우리는 마법의 문자열을 사랑 ;-)) 해당 테이블에 변화를 수신 :

private void DatabasePropertyChanged(object sender, PropertyChangedEventArgs e) 
{ 
    if(e.PropertyName == "Tours") 
    { 
    LoadTourList(); 
    } 
} 

내가에서 원하는 레코드를 선택 다음 테이블에 새 데이터가 있음을 알리십시오.

public void LoadTourList() 
{ 
    AllTours = (from t in Database.Instance.Tours 
    select new TourViewModel(t)).ToList(); 

    RaisePropertyChanged("AllTours"); 
} 

그리고 마지막으로 ViewMod elBase, RaisePropertyChanged가 디스패치해야하는지 확인하는 것이 가장 좋습니다. 내 "SafeDispatch"방법은 거의 MVVMlight의 것과 동일합니다 :

private void RaisePropertyChanged(string property) 
{ 
    if (PropertyChanged != null) 
    { 
    UiHelper.SafeDispatch(() => 
     PropertyChanged(this, new PropertyChangedEventArgs(property))); 
    } 
} 

이 내 코드에서 완벽하게 작동, 나는 상당히 깔끔 생각?

마지막으로, 전문가를위한 추가 정보 : WP7에서는 IsIndeterminate = True 인 ProgressBar를 페이지에 추가하는 것이 좋을 수 있습니다.이 경우 "점선으로 된"진행률 표시 줄이 표시됩니다. 그런 다음 ViewModel을 처음로드 할 때 "ProgressBarVisible"속성을 Visible로 설정하고 연결된 PropertyChanged 이벤트를 발생시킬 수 있습니다. ProgressBar의 가시성을이 ViewModel property에 바인드합니다. Database PropertyChanged 이벤트가 발생하면 가시성을 Collapsed로 설정하여 진행 표시 줄을 사라지게합니다.

이렇게하면 직렬화가 실행되는 동안 화면 상단에 "IsIndeterminate"진행률 표시 줄이 나타납니다. 좋은!

+0

성능에 미치는 영향을 두 번 확인하는 것을 잊지 마십시오. indeterminate 진행 막대 사용 : http://www.jeff.wilcox.name/2010/08/progressbarperftips2/ –

+0

명확하게 IsDeterminte = False가 표시되지 않을 때 설정합니다. – Micah

+0

SafeDispatch의 소스가 좋을 것입니다. – Sam

0

내가 전에 WP7 개발하지 않은,하지만 난 this article that might be useful을 발견입니다! 나는 그것이 :) 도움이 희망

public DinnersViewModel(IDinnerCatalog catalog) 
{ 
    theCatalog = catalog; 
    theCatalog.DinnerLoadingComplete += 
     new EventHandler<DinnerLoadingEventArgs>(
       Dinners_DinnerLoadingComplete); 
} 

public void LoadDinners() 
{ 
    theCatalog.GetDinners(); 
} 

void Dinners_DinnerLoadingComplete(
    object sender, DinnerLoadingEventArgs e) 
{ 
    // Fire Event on UI Thread 
    View.Dispatcher.BeginInvoke(() => 
     { 
      // Clear the list 
      theDinners.Clear(); 

      // Add the new Dinners 
      foreach (Dinner d in e.Results) 
       theDinners.Add(d); 

      if (LoadComplete != null) 
       LoadComplete(this, null); 
     }); 
} 

: 여기

는 당신에게 다른 스레드에서 UI에 이벤트를 발생하는 방법에 대한 좋은 아이디어를 줄 것이다 기사에서 식사 철학자 샘플 코드입니다.

혼란스러운 것 : 당신이 도우미를 사용하여 이벤트를 제기하면 VS2010이 충돌합니다 ... 충돌 할 때 정확히 무엇을보고 있습니까? 예외가 있습니까?

+0

내가 참조한 소스 코드를 찾는 데 문제가 있습니다. 링크가 있습니까? 나는 Cataget.GetDinners()가 어떻게 구현되는지보고 흥미 롭습니다. –

+0

@ 제프, 내가 기사 (내 대답의 첫 문장)에 링크 된 기사의 URL은 다음과 같습니다. http://chriskoenig.net/series/wp7/ – Kiril

0

제프, 나는 아직도이 물건을 알아 내고 있습니다. 나는 비슷한 질문을 게시하고 간단한 샘플을 작성하여 직접 대답했다. 여기 :

A super-simple MVVM-Light WP7 sample?

요약은 다음과 같습니다

1) 나는 ViewModelBase에서 내 모델 (예 내 모델)을 산출했다. 이것은 Mvvm-Light의 메시징 구현과 편리한 INotifyPropertyChanged을 제공합니다. 당신은 이것이 "순수한"것이 아니라고 주장 할 수 있습니다. 그러나 나는 그것이 중요하다고 생각하지 않습니다.

2) Mvvm-Light DispatcherHelper.CheckBeginInvokeOnUI 도우미를 사용했습니다 (내 모델, 내 ViewModel에서와 동일).

희망이 도움이됩니다.