2013-06-12 36 views
5

Tôi gặp sự cố khi nhận dữ liệu từ db và hiển thị trong giao diện người dùng không đồng bộ. Tôi đang sử dụng ánh sáng MVVM, khi tôi bấm nút, hành động được kích hoạt trong ViewModel:Cập nhật giao diện người dùng không đồng bộ từ ViewModel trong WPF

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

Tại một số điểm GetFriendsListCompleted được gọi bằng sợi nền notifing viewmodel công việc đó được thực hiện. Tại thời điểm này tôi cần cập nhật ListBox ItemSource. Nhưng khi tôi cố gắng cập nhật là tôi nhận được “Các thread gọi không thể truy cập đối tượng này vì một thread khác nhau sở hữu nó” Tôi đã thử Dispatcher.CurrentDispatcher.Invoke(), App.Current.Dispatcher.Invoke() và ma thuật khác, nhưng nó vẫn không hoạt động.

Tôi đã cố gắng cung cấp bộ điều phối giao diện người dùng cho ViewModel và sau đó gọi nó từ đó - không hoạt động.

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. 
     } 
    } 

Tôi cố gắng để thay đổi dòng này để

Dispatcher.Invoke (DispatcherPriority.Normal, Hành động mới ( () => this.FriendsList.View.Refresh())); - vẫn giống nhau.

Tôi đang sử dụng Hộp danh sách Telerik để hiển thị các mục. FriendList là CollectionViewSource (http://www.telerik.com/help/wpf/radlistbox-overview.html). Nó hoạt động khi tôi sử dụng ví dụ Telerik từ WPF Control Ví dụ. Các sự cố bắt đầu xảy ra khi tôi sử dụng các phương thức không đồng bộ của mình. Loại chế độ xem là System.ComponentModel.ICollectionView được sử dụng để lọc và nhóm.

Tôi cũng đã cố gắng chỉ gán thuộc tính ObservableCollection cho Mục của ListBox và nó cũng không hoạt động.

Một chút biết thêm chi tiết về cách _redisModel.GetFriendsListAsync hoạt động: Cuối cùng (sau khi tất cả chuỗi các cuộc gọi) nó kết thúc ở đây:

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 
    } 
}); 

Trong viewmodel tôi có phương pháp:

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())); 
      } 
    } 

Ai có thể giúp tôi với điều này? Cảm ơn bạn

+0

@Robert Kruszewski – LucasSeveryn

+0

Chỉnh sửa câu hỏi của bạn và thêm một số bối cảnh cho câu hỏi của bạn. Loại 'FriendsList' là gì. Thuộc tính 'View' mà bạn đang truy cập từ VM là gì? – Viv

Trả lời

4

Bạn đang tạo CollectionViewSource trong một chuỗi và làm mới trong chuỗi khác (chuỗi điều phối). Cập nhật 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

Tuyệt vời! Nó đã làm việc! Cảm ơn nhiều. Nhưng hiện tại tôi đang chuyển App.Current.Điều phối viên vào ViewModel bên trong CodeBehind. Có cách tiếp cận trang nhã hơn không? – Andy

+0

@Andy vui lòng kiểm tra câu trả lời được chấp nhận [câu hỏi này] (http://stackoverflow.com/questions/2354438/how-to-pass-the-ui-dispatcher-to-the-viewmodel) – sthotakura

+0

Tôi đã thử và không thực hiện được ' t làm việc. Nó không thành công sau khi tôi thêm một tham số mới để xây dựng ViewModel. MEF không thể tìm thấy. Thật lạ vì tôi đã có một tham số - thành phần DAL của tôi và nó hoạt động. Tôi nghĩ rằng đó là một cái gì đó để làm với lớp WpfContext đó được khai báo trong giao diện người dùng và thứ tự của initialisation. – Andy

0

Bạn chưa hiển thị bất kỳ mã nào thực sự chạy trên chuỗi nền khi hoàn thành nhưng tôi đoán rằng trong đó bạn đang tạo đối tượng bộ sưu tập mà bạn đang cố gán cho CollectionView. Khi CV cố gắng cập nhật (trên chuỗi giao diện người dùng) từ cuộc gọi Làm mới của bạn, nó sẽ cố gắng sử dụng bộ sưu tập thuộc sở hữu của chủ đề khác.

Nếu bạn bao gồm mã có liên quan, việc nói chắc chắn sẽ dễ dàng hơn.

+0

Đoán của bạn khá chính xác. Tôi đã cập nhật các câu hỏi với nhiều mã hơn. – Andy

Các vấn đề liên quan