在WPF 4.5中跨線程更新集合


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

解決這個問題的一個傳統方式是把對集合的修改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);

    ThreadPool.QueueUserWorkItem(async _ =>
        {
            await Task.Delay(1000);
            collection.Add(DateTime.Now.ToString());
        });

這樣,對集合訪問就沒有UI線程限制了,要方便不少。沒有細研究其內部實現機制,貌似是通過加鎖實現的。

與之相對的是,還提供了一個去使能集合同步的函數BindingOperations.DisableCollectionSynchronization網上的文章說是使用完后要用這個函數去使能集合同步,否則會以為集合的引用沒有釋放導致內存泄漏。不過,我自己寫代碼試了一下,即使不用它解除鎖定,集合對象還是能正常釋放的,應該保存的只是一個弱引用,不主動解除鎖定也沒有內存泄漏問題。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM