2010-02-19 21 views
26

Tôi có một số ObservableCollection trong lớp học của mình. Và thêm vào lớp của tôi, tôi có một chủ đề. Từ chủ đề này, tôi muốn thêm vào số ObservableCollection của mình. Nhưng tôi không thể thực hiện việc này:Quan sátCollection and threading

Loại CollectionView này không hỗ trợ thay đổi SourceCollection của nó từ một chuỗi khác với chuỗi điều phối.

Lưu ý rằng điều này không xảy ra từ chuỗi giao diện người dùng, vì vậy tôi không có quyền truy cập vào điều phối viên.

Trả lời

16

Cách tiếp cận của JaredPar là phương pháp hợp lệ. Một cách tiếp cận khác đáng xem xét là sử dụng một sợi an toàn ObservableCollection thay vì được xây dựng trong ObservableCollection. Có một vài triển khai ngoài kia, nhưng Sasha Barber's implementationCLinq Continuous Collection class là một số ý tưởng tốt hơn trong quan điểm của tôi. Bên trong, các lớp này về cơ bản sử dụng cách tiếp cận được vạch ra bởi JaredPar, nhưng đóng gói nó bên trong lớp sưu tập.

+0

Cá nhân tôi không thể làm cho nó hoạt động với các liên kết được cung cấp. Tôi cần sử dụng cách tiếp cận của JaredPas'a mà bạn đã đề cập. –

+0

Hãy thử liên kết sau đây cung cấp giải pháp an toàn chủ đề hoạt động từ bất kỳ chuỗi nào và có thể bị ràng buộc bởi nhiều chuỗi giao diện người dùng: http://www.codeproject.com/Articles/64936/Multithreaded-ObservableImmutableCollection – Anthony

+0

Bài viết bạn tham chiếu AnthonyPaulO yêu cầu gói NuVet không thể thay đổi bộ sưu tập và chỉ hoạt động với .NET4.5. Có bất cứ điều gì tương tự xung quanh cho. NET4.0? – Dave

13

Cách tốt nhất để giải quyết vấn đề này là chuyển đối tượng Dispatcher đến phương pháp bắt đầu của chuỗi nền.

void DoBackgroundOperation(ObservableCollection<SomeType> col) { 
    var dispatcher = Dispatcher.CurrentDispatcher; 
    ThreadStart start =() => BackgroundStart(dispatcher, col); 
    var t = new Thread(start); 
    t.Start(); 
} 

private static void BackgroundStart(
    Dispatcher dispatcher, 
    ObservableCollection<SomeType> col) { 
    ... 
    SomeType t = GetSomeTypeObject(); 
    Action del =() => col.Add(t); 
    dispatcher.Invoke(del); 
} 

Bây giờ sau này khi bạn cần thêm vào bộ sưu tập, bạn có thể sử dụng đối tượng UI Dispatcher.

Khi @Reed chỉ ra, một giải pháp tổng quát hơn là đạt được bằng cách sử dụng SynchronizationContext. Dưới đây là mẫu kiểu chức năng sử dụng SynchronizationContext để tạo đại biểu chịu trách nhiệm thêm các giá trị mới. Điều này có lợi thế là ẩn cả bộ sưu tập và mô hình luồng từ mã tạo đối tượng.

void DoBackgroundOperation(ObservableCollection<SomeType> col) { 
    var context = SynchronizationContext.Current; 
    Action<SomeType> addFunc = (SomeType st) => context.Send(() => col.Add(st), null); 
    ThreadStart start =() => BackgroundStart(addFunc); 
    var t = new Thread(start); 
    t.Start(); 
} 

private static void BackgroundStart(Action<SomeType> addFunc) { 
    ... 
    SomeType t = GetSomeTypeObject(); 
    addFunc(t); 
} 
+3

1: Ngoài ra, các phương pháp tương tự có thể được thực hiện bằng cách sử dụng SynchronizationContext.Current thay vì dispatcher, nếu bạn không muốn dùng một phụ thuộc WPF (ví dụ: bạn cũng muốn sử dụng mã này trong Windows Forms). –

+0

@Reed, đã thêm giải pháp với 'SynchronizationContext' có hương vị chức năng. – JaredPar

+0

Cảm ơn bạn đã trả lời. Tôi sẽ nhìn vào ngày mai vì nó là 01:30 sáng ở đây. – ErikTJ