2010-09-02 31 views
9

Ok, gần đây tôi đã triển khai một nhân viên nền để thực hiện lưu và tải dữ liệu.Cập nhật một ObservableCollection với nhân viên nền trong MVVM

Tuy nhiên, việc này để làm việc trên lệnh lưu đã tỏ ra khó khăn. Về cơ bản, lệnh lưu của tôi tạo ra một sự kiện, thông báo cho một mô hình xem bộ sưu tập, rằng một Item đã được thêm vào và mục đó sẽ được thêm vào ObservableCollection của riêng nó.

Tại thời điểm này, tôi nhận được ngoại lệ thông thường nói rằng tôi KHÔNG thể cập nhật ICollection trên một chuỗi khác. Tôi đã thử tạo một loại danh sách mới gọi là Dispatcher.Invoke, tuy nhiên điều này vẫn tạo ra cùng một ngoại lệ.

Tôi đã tự hỏi liệu có ai khác có bất kỳ đề xuất nào về cách tốt nhất để giải quyết vấn đề này không?

Vì vậy, hiện tại tôi có một lớp kế thừa từ ObservableCollection:

public class ThreadSafeObservableCollection<T> : ObservableCollection<T> 
{ 
    public ThreadSafeObservableCollection(List<T> collection) 
     : base(collection) 
    { 
     dispatcher = Dispatcher.CurrentDispatcher; 
     rwLock = new ReaderWriterLock(); 
    } 

    protected override void InsertItem(int index, T item) 
    { 
     if (dispatcher.CheckAccess()) 
     { 
      if (index > this.Count) 
       return; 
      LockCookie c = rwLock.UpgradeToWriterLock(-1); 
      base.InsertItem(index, item); 
      rwLock.DowngradeFromWriterLock(ref c); 
     } 
     else 
     { 
      object[] obj = new object[] { index, item }; 
      dispatcher.Invoke(
       DispatcherPriority.Send, 
       (SendOrPostCallback)delegate { InsertItemImpl(obj); }, 
       obj); 
     } 
    } 

sau đó tôi có một lớp xem mô hình mà có một nền công nhân thực hiện chức năng tiết kiệm.

Khi lưu xong, sự kiện sẽ được kích hoạt sang một mô hình chế độ xem khác để cập nhật danh sách của nó.

protected override void OnObjectAddedToRepository(object sender, ObjectEventArgs<cdAdministrators> e) 
    { 
     Dispatcher x = Dispatcher.CurrentDispatcher; 
     var viewModel = new AdministratorViewModel(e.EventObject, DataAccess); 
     viewModel.RecentlyAdded = true; 
     viewModel.ItemSelected += this.OnItemSelected; 
     this.AllViewModels.Add(viewModel); 
     RecentlyAddedViewModel = viewModel; 

     OnPropertyChanged(null); 
    } 

Cả hai danh sách đều được tạo bởi một chuỗi công nhân nền riêng biệt.

Trả lời

7

Nơi bạn đã có mã để thêm mục vào bộ sưu tập có thể quan sát (có lẽ trong kiểu xem), hãy gọi Add gọi trong cuộc gọi Dispatcher.BeginInvoke. Phải thừa nhận rằng có nghĩa là mô hình xem cần biết về điều phối viên, sau đó trở nên khó xử để kiểm tra ... may mắn thay, không quá khó để giới thiệu giao diện IDispatcher của riêng bạn và sử dụng tiêm phụ thuộc theo cách thông thường.

+0

Hi Jon, Cảm ơn trả lời của bạn, tôi đã có một đối tượng bộ sưu tập, mà kế thừa từ ObserveableCollection trên InsertItem này không Dispatcher.CheckAccess nếu sai thì không Dispather.BeginInvoke, tuy nhiên điều này vẫn chưa làm việc ?? – jpgooner

+0

@jpgooner: Bạn có chắc chắn rằng mã thực sự đang được sử dụng không? Bạn có thể đưa ra một ví dụ ngắn nhưng đầy đủ để chứng minh vấn đề? –

+0

Tôi đã bổ sung thêm chi tiết ở trên, hãy cho tôi biết nếu bạn cần nữa, tôi vẫn còn mới để stackoverflow – jpgooner

3

Làm thế nào về điều này?

public class ThreadSafeObservableCollection<T> : ObservableCollection<T> 
{ 
    private SynchronizationContext SynchronizationContext; 

    public ThreadSafeObservableCollection() 
    { 
     SynchronizationContext = SynchronizationContext.Current; 

     // current synchronization context will be null if we're not in UI Thread 
     if (SynchronizationContext == null) 
      throw new InvalidOperationException("This collection must be instantiated from UI Thread, if not, you have to pass SynchronizationContext to con        structor."); 
    } 

    public ThreadSafeObservableCollection(SynchronizationContext synchronizationContext) 
    { 
     if (synchronizationContext == null) 
      throw new ArgumentNullException("synchronizationContext"); 

     this.SynchronizationContext = synchronizationContext; 
    } 

    protected override void ClearItems() 
    { 
     this.SynchronizationContext.Send(new SendOrPostCallback((param) => base.ClearItems()), null); 
    } 

    protected override void InsertItem(int index, T item) 
    { 
     this.SynchronizationContext.Send(new SendOrPostCallback((param) => base.InsertItem(index, item)), null); 
    } 

    protected override void RemoveItem(int index) 
    { 
     this.SynchronizationContext.Send(new SendOrPostCallback((param) => base.RemoveItem(index)), null); 
    } 

    protected override void SetItem(int index, T item) 
    { 
     this.SynchronizationContext.Send(new SendOrPostCallback((param) => base.SetItem(index, item)), null); 
    } 

    protected override void MoveItem(int oldIndex, int newIndex) 
    { 
     this.SynchronizationContext.Send(new SendOrPostCallback((param) => base.MoveItem(oldIndex, newIndex)), null); 
    } 
} 
2

Tôi đã tìm thấy một blog post sử dụng Trình điều phối để quản lý tất cả các phương pháp của ObeservableCollection. Dưới đây là một mã của mã, xem post cho toàn bộ lớp học.

public class DispatchingObservableCollection<T> : ObservableCollection<T> 
{ 
    /// <summary> 
    /// The default constructor of the ObservableCollection 
    /// </summary> 
    public DispatchingObservableCollection() 
    { 
     //Assign the current Dispatcher (owner of the collection) 
     _currentDispatcher = Dispatcher.CurrentDispatcher; 
    } 

    private readonly Dispatcher _currentDispatcher; 

    /// <summary> 
    /// Executes this action in the right thread 
    /// </summary> 
    ///<param name="action">The action which should be executed</param> 
    private void DoDispatchedAction(Action action) 
    { 
     if (_currentDispatcher.CheckAccess()) 
      action(); 
     else 
      _currentDispatcher.Invoke(DispatcherPriority.DataBind, action); 
    } 

    /// <summary> 
    /// Clears all items 
    /// </summary> 
    protected override void ClearItems() 
    { 
     DoDispatchedAction(() => base.ClearItems()); 
    } 

    /// <summary> 
    /// Inserts a item at the specified index 
    /// </summary> 
    ///<param name="index">The index where the item should be inserted</param> 
    ///<param name="item">The item which should be inserted</param> 
    protected override void InsertItem(int index, T item) 
    { 
     DoDispatchedAction(() => base.InsertItem(index, item)); 
    } 
+0

Ví dụ tốt! Chỉ cần một sửa chữa nhỏ: bảo vệ ghi đè void InsertItem (int index, T item) {DoDispatchedAction (() => BaseInsertItem (chỉ mục, mục)); } là trong thực tế bảo vệ ghi đè void InsertItem (int index, T item) {DoDispatchedAction (() => base.InsertItem (chỉ mục, mục)); } –

+0

Cảm ơn. Tôi không chắc tại sao tôi lại tạo một phương thức một cách rõ ràng và sử dụng một phương thức nặc danh cho ví dụ thứ hai. Tôi đã làm sạch chúng. – chilltemp

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