天天看點

在WPF 4.5中跨線程更新集合

原文:

在WPF 4.5中跨線程更新集合

WPF中一個非常強大的功能是資料綁定,我們可以把一個集合綁定到ListBox中,當集合的資料發生變更時,ListBox界面也會同步變更。本身這是一個非常美好的事情,但是美中不足的是:當把集合綁定到ListBox中的時候,集合也順帶繼承了ListBox的這種不能誇線程通路的限制。例如,如下代碼就會抛出跨線程通路異常。

在WPF 4.5中跨線程更新集合

解決這個問題的一個傳統方式是把對集合的修改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。網上的文章說是使用完後要用這個函數去使能集合同步,否則會以為集合的引用沒有釋放導緻記憶體洩漏。不過,我自己寫代碼試了一下,即使不用它解除鎖定,集合對象還是能正常釋放的,應該儲存的隻是一個弱引用,不主動解除鎖定也沒有記憶體洩漏問題。