2010-06-05 24 views
8

Trong một ứng dụng WPF đa luồng, nó là not possible để cập nhật một ObservableCollection từ một chuỗi khác với chuỗi cửa sổ WPF.Tại sao không thể cập nhật ObservableCollection từ một chuỗi khác?

Tôi biết there are workarounds, do đó, câu hỏi của tôi không phải là cách tránh "Loại bộ sưu tập này không hỗ trợ thay đổi đối với SourceCollection của nó từ chuỗi khác với chủ đề của Điều phối viên".

Câu hỏi của tôi là, tại sao có ngoại lệ như vậy? Tại sao không thể cho phép cập nhật bộ sưu tập từ bất kỳ chuỗi nào?

Cá nhân, tôi không thấy bất kỳ lý do gì để chặn cập nhật giao diện người dùng khi ObservableCollection được thay đổi từ các chủ đề khác. Nếu hai luồng (bao gồm cả các đối tượng song song) đang truy cập cùng một đối tượng, người ta nghe những thay đổi của thuộc tính đối tượng thông qua các sự kiện, cái kia thay đổi, nó sẽ luôn hoạt động, ít nhất nếu khóa được sử dụng đúng cách. Vậy, lý do là gì?

+0

.NET 4.5 thêm chức năng để trợ giúp các thao tác chéo trên 'ObservableCollection'; xem [Làm cách nào để cập nhật ObservableCollection qua chuỗi công nhân?] (http://stackoverflow.com/q/2091988/50079) – Jon

+0

Thử liên kết sau 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 thông qua nhiều chủ đề giao diện người dùng: http://www.codeproject.com/Articles/64936/Multithreaded-ObservableImmutableCollection – Anthony

Trả lời

15

Đầu tiên ... Tôi cảm thấy nỗi đau của bạn. Các chủ đề Ui hạn chế có thể là một nỗi đau ...

Tại sao bạn không thể cập nhật một Ui phần tử từ a thread khác so với cái nó được tạo ra trên ?

Câu hỏi của tôi là tại sao có ngoại lệ ?

Tóm lại, lịch sử. Windows đã được khoảng một thời gian và cách một số phần của công việc Gui được nhúng trong các công nghệ như COM và tương tự .... vì vậy việc thay đổi nó không phải là tầm thường ... sẽ rất dễ dàng để phá vỡ một cái gì đó. Có nhiều vấn đề khác tôi chắc chắn ... nhưng ai đó thông minh hơn tôi sẽ cần phải giải thích chúng. Tôi tin rằng nhóm WPF thực sự muốn loại bỏ hạn chế này và họ đã làm việc ở đó khá khó khăn ... cuối cùng tôi nghĩ rằng số lượng thay đổi hệ điều hành cốt lõi cần được unworkable ... vì vậy họ di chuyển trên .... chuột.

Tại sao không thể cho phép cập nhật bộ sưu tập từ bất kỳ chuỗi nào?

Đã và đang có thể ... Làm cho một thứ gì đó an toàn cho chủ đề luôn có chi phí một chút về hiệu suất và thêm độ phức tạp. Trong hầu hết các trường hợp, ứng dụng không gọi cho truy cập đa luồng. Điều quan trọng là phải hiểu rằng, đối với hầu hết các phần, Microsoft chơi theo các quy tắc tương tự chúng tôi làm và các hạn chế tương tự. Nếu họ đã làm cho ObservableCollection thread-safe ... họ sẽ sử dụng cùng một công cụ chúng ta có ... khóa, màn hình, vv Họ không thể phá vỡ quy tắc thread Ui nhiều hơn chúng ta có thể ... không có phép thuật ... các quy tắc tương tự.

Tôi biết có cách giải quyết, vì vậy câu hỏi của tôi không phải là làm thế nào để tránh được những "Đây loại CollectionView không thay đổi hỗ trợ cho SourceCollection của nó từ một sợi khác nhau từ thread dispatcher" ngoại lệ.

Không có cách giải quyết ... Không có cách nào giải quyết. ObservableCollection bị hỏng..nó không chỉ an toàn cho luồng. Bạn phải làm cho nó, hoặc truy cập vào nó, thread-safe. Điều này cũng tương tự đối với bất kỳ thứ gì không an toàn chỉ ... nếu bạn cần nó an toàn chỉ sau đó làm cho nó như vậy. Nếu bạn đang sử dụng chủ đề thì bạn biết về khóa và như vậy ... sử dụng chúng ... đó là những gì họ đang có.

... cập nhật khối UI khi ObservableCollection được thay đổi từ đề khác .... nó sẽ luôn luôn làm việc, ít nhất nếu khóa được sử dụng đúng cách ....

Nếu ổ khóa được sử dụng đúng cách ... Chính xác! Một lần nữa, Microsoft có thể đã đặt những khóa này vào nhưng họ đã không và vì những lý do rất tốt. Bạn có thể đặt các khóa vào. Hoặc bạn sử dụng các chiến thuật khác sẽ cung cấp cho bạn truy cập an toàn chỉ .... nhiều tùy chọn.

Task Parallel Library trong .net4.0 cung cấp một số công cụ mới để giải quyết những vấn đề này. Việc có thể thiết lập bối cảnh cho một nhiệm vụ hoặc một chủ đề đặc biệt hữu ích ...

// get the Ui thread context 
    _uiScheduler = TaskScheduler.FromCurrentSynchronizationContext(); 

    Action DoInBackground = new Action(() => 
    { 
    /*...In the background... 
     ...process some data for an ObservableCollection...*/ 
    }); 

    Action DoOnUiThread = new Action(() => 
    { 
    /*...On the UI thread... 
     ...read/write data to an ObservableCollection...*/ 
    }); 

    // start the background task 
    var t1 = Task.Factory.StartNew(() => DoInBackground()); 
    // when t1 is done run t1..on the Ui thread. 
    var t2 = t1.ContinueWith(t => DoOnUiThread(), _uiScheduler); 

Đừng nghĩ về các yêu cầu về ái lực của các yếu tố Ui như một cái gì đó để làm việc ... nó chỉ là cách nó hoạt động.

C# và .Net có nhiều công cụ mà bạn có thể sử dụng để tạo luồng ít hơn một cơn ác mộng. Sử dụng chúng ... chúng có thể vui vẻ.

Tôi sẽ hút thuốc.

10

Nếu bộ sưu tập của bạn bị ràng buộc với các yếu tố giao diện người dùng, các yếu tố giao diện người dùng đó đang nghe trên sự kiện CollectionChanged của bộ sưu tập và sự kiện này được nêu lên trên chủ đề mà bạn đang cập nhật bộ sưu tập.

Vì vậy, vấn đề là với các yếu tố giao diện người dùng, chỉ có thể truy cập được từ chuỗi mà trên đó chúng được tạo và không phải với chính bộ sưu tập.

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