2013-06-12 1 views
5

db에서 데이터를 가져와 비동기 적으로 UI에 표시하는 데 문제가 있습니다. 내가 MVVM의 빛을 사용하고 I 버튼을 클릭하면, 액션은 뷰 모델에 트리거 : 해당 작업이 완료 뷰 모델WPF의 ViewModel에서의 비동기 UI 업데이트

private void SearchQuery(string query) 
    { 
     _redisModel.GetFriendsListAsync(query); 
    } 

어떤 시점에서 GetFriendsListCompleted가 배경 스레드 notifing에 의해 호출됩니다. 이 시점에서 ListBox ItemSource를 업데이트해야합니다. 내가 업데이트하려고하면하지만 는 "다른 스레드가 그것을 소유하고 있기 때문에 호출 스레드가이 개체에 액세스 할 수 없습니다"얻을 것입니다 나는 시도 Dispatcher.CurrentDispatcher.Invoke(), App.Current.Dispatcher.Invoke() 그리고 다른 마술,하지만 여전히 작동하지 않습니다.

ViewModel에 UI 디스패처를주고 그곳에서 호출하려고했습니다. 작동하지 않았습니다.

private string filterText = string.Empty; 
    public string FilterText 
    { 
     get { return filterText; } 
     set 
     { 
      filterText = value; 
      this.RaisePropertyChanged(() => this.FilterText); 

      this.FriendsList.View.Refresh(); // Here where exception is happening. 
     } 
    } 

제가

Dispatcher.Invoke (DispatcherPriority.Normal 새로운 액션 ( () => this.FriendsList.View.Refresh()))이 줄을 변경하려고; - 여전히 똑같아.

Telerik ListBox를 사용하여 항목을 표시하고 있습니다. FriendList는 CollectionViewSource (http://www.telerik.com/help/wpf/radlistbox-overview.html)입니다. WPF 컨트롤 예제의 Telerik 예제를 사용할 때 작동합니다. 비동기 메서드를 사용할 때 문제가 발생하기 시작합니다. 보기의 형식은 System.ComponentModel.ICollectionView이며 필터링 및 그룹화에 사용됩니다.

ObservableCollection을 ListBox의 Items 속성에 할당하려고 시도했으나 작동하지 않습니다. 그것은 여기에 끝납니다 (전화의 모든 체인 후) 결국 :

A는 더 _redisModel.GetFriendsListAsync가 작동하는 방법에 대한 자세한 내용을 비트 뷰 모델에서

public GetAsyncResult(Func<T> workToBeDone, Action<IAsyncResult> cbMethod, Object state) 
{ 
    _cbMethod = cbMethod; 
    _state = state; 
    QueueWorkOnThreadPool(workToBeDone); 
} 

ThreadPool.QueueUserWorkItem(state => 
{ 
    try 
    { 
    _result = workToBeDone(); 
    } 
    catch (Exception ex) 
    { 
     _exception = ex; 
    } 
    finally 
    { 
    UpdateStatusToComplete(); //1 and 2 
    NotifyCallbackWhenAvailable(); //3 callback invocation 
    } 
}); 

내가 가진 방법 :

private void GetFriendsListCompleted(object sender, ResultsArgs<Friend> e) 
    { 
     if (!e.HasError) 
     { 
      var curr = e.Results; 
      if (curr != null) 
      { 
       this.FriendsList= new CollectionViewSource(); 

       this.FriendsList.Source = list; 
       this.FriendsList.Filter += this.FriendFilter; 
       FilterText = ""; 

       Dispatcher.Invoke(DispatcherPriority.Normal, new Action(

         () => this.FriendsList.View.Refresh())); 
      } 
    } 

아무도 도와 주실 수 있습니까? 감사합니다.

+0

@Robert Kruszewski – LucasSeveryn

+0

편집 질문을 업데이트하고 귀하의 질문에 어떤 컨텍스트를 추가 할 수 있습니다. 'FriendsList'의 종류는 무엇입니까? VM에서 접근하는'View' 속성은 무엇입니까? – Viv

답변

4

하나의 스레드에 CollectionViewSource을 만들고 다른 스레드 (디스패처 스레드)에서 새로 고치고 있습니다. 당신의 GetFriendsListCompleted

private void GetFriendsListCompleted(object sender, ResultsArgs<Friend> e) 
{ 
    if (!e.HasError) 
    { 
     var curr = e.Results; 
     if (curr != null) 
     { 
      Dispatcher.Invoke(DispatcherPriority.Normal, new Action(
        () => { 
        this.FriendsList= new CollectionViewSource(); 
        this.FriendsList.Source = list; 
        this.FriendsList.Filter += this.FriendFilter; 
        FilterText = ""; 
        this.FriendsList.View.Refresh(); 
        })); 
     } 
    } 
} 
+0

좋아요! 그것은 효과가있다! 고맙습니다. 하지만 현재는 App.Current를 전달하고 있습니다.CodeBehind 내의 ViewModel에 대한 Dispatcher입니다. 보다 우아한 접근 방식이 있습니까? – Andy

+0

@Andy 허용되는 답변을 확인하십시오 [이 질문] (http://stackoverflow.com/questions/2354438/how-to-pass-the-ui-dispatcher-to-the-viewmodel) – sthotakura

+0

나는 시험해 보았고, 일하지 마라. ViewModel 생성자에 새 매개 변수를 추가하면 실패합니다. MEF가 찾지 못했습니다. 그것은 하나의 매개 변수가 이미 있기 때문에 이상합니다. DAL 구성 요소가 작동하고 있습니다. WpfContext 클래스가 UI 및 초기화 순서로 선언된다는 것과 관련이 있다고 생각합니다. – Andy

0

완료시 백그라운드 스레드에서 실제로 실행되고있는 코드는 표시하지 않았지만이 코드에서 사용자가 할당하려고하는 콜렉션 개체를 만들고있는 것으로 추측하고 있습니다. CollectionView. CV가 새로 고침 호출에서 UI 스레드에서 업데이트하려고하면 다른 스레드가 소유 한 컬렉션을 사용하려고 시도합니다.

관련 코드를 포함하면 확실하게 말할 수 있습니다.

+0

당신의 추측은 아주 정확합니다. 더 많은 코드로 질문을 업데이트했습니다. – Andy

관련 문제