原文:
在WPF 4.5中跨線程更新集合WPF中一個非常強大的功能是資料綁定,我們可以把一個集合綁定到ListBox中,當集合的資料發生變更時,ListBox界面也會同步變更。本身這是一個非常美好的事情,但是美中不足的是:當把集合綁定到ListBox中的時候,集合也順帶繼承了ListBox的這種不能誇線程通路的限制。例如,如下代碼就會抛出跨線程通路異常。
![](https://img.laitimes.com/img/_0nNw4CM6IyYiwiM6ICdiwiIn5GcuEGOkZDOxEzYjlDNmhzN4QmN5YjMwUmYiRWO1QGZllDZfdWbp9CXt92Yu4GZjlGbh5SZslmZxl3Lc9CX6MHc0RHaiojIsJye.png)
解決這個問題的一個傳統方式是把對集合的修改Post到UI線程中來,改成如下形式。
ThreadPool.QueueUserWorkItem(async _ =>
{
await
Task.Delay(1000);
this.Dispatcher.Invoke(new
Action(()=>collection.Add(DateTime.Now.ToString())), null);
});
不過這種寫法顯得很繁瑣,在.Net 4.5提供了新的一種線程安全通路機制,那就是用
BindingOperations.EnableCollectionSynchronization使能集合同步:
var collection = new
ObservableCollection<string>();
listBox.ItemsSource = collection;
var lockObj = new
object();
BindingOperations.EnableCollectionSynchronization(collection, lockObj);
Task.Delay(1000);
collection.Add(DateTime.Now.ToString());
這樣,對集合通路就沒有UI線程限制了,要友善不少。沒有細研究其内部實作機制,貌似是通過加鎖實作的。
與之相對的是,還提供了一個去使能集合同步的函數BindingOperations.DisableCollectionSynchronization。網上的文章說是使用完後要用這個函數去使能集合同步,否則會以為集合的引用沒有釋放導緻記憶體洩漏。不過,我自己寫代碼試了一下,即使不用它解除鎖定,集合對象還是能正常釋放的,應該儲存的隻是一個弱引用,不主動解除鎖定也沒有記憶體洩漏問題。