How to disconnect UI and Data in WPF (CachedObservableCollection) and some updates regarding ThreadSafeObservableCollection
Sometimes, we want to “freeze” current displayed collection, while the original collection keep being updates. How to do it? There are some ways to get such functionality. One is to use CollectionView DeferRefresh method and release (dispose) it after you finished. However, it can not provide us with full functionality, due to fact, that the lock applies on original collection, thus we wont update it until the lock will be released.
Another approach is to keep disconnected underlying collection, that synchronized with the original collection while it reaches “cache limit”. After reaching it, we’ll disconnect the original collection, keeping to be updated and reconnect (or, even refill) the underlying collection when possible.

Let’s see the example of such functionality. We have the underlying collection, that rapidly changing in background (another thread)
class MyData : ThreadSafeObservableCollection<string>
{
public MyData()
{
ThreadPool.QueueUserWorkItem(delegate
{
int i = 0;
while (true)
{
base.Add(string.Format(“Test {0}”, i++));
Thread.Sleep(100);
if (base.Count > 10)
base.RemoveAt(0);
}
});
Also, we have another collection, that initialized by original collection and number of items should be cached.
dta = Resources["data"] as MyData;
cache = new CachedObservableCollection<string>(dta,5);
Then, we just create CollectionView to be able to sort/filter displayed data and bind it into ListBox
CollectionView view = new CollectionView(cache);
Binding b = new Binding();
b.Source = view;
lst.SetBinding(ListBox.ItemsSourceProperty, b);
So, what CachedObservableCollection<T> actually doing? First of all, it holds the reference to our original data source. It also, subscribes to CollectionChanged event of the original source in order to check whether it reach the cache limit.
public CachedObservableCollection(ObservableCollection<T> collection, int maxItems):base()
{
m_cached = collection;
m_cached.CollectionChanged += new System.Collections.Specialized.NotifyCollectionChangedEventHandler(m_cached_CollectionChanged);
MaxItems = maxItems;
}
It it is, we just disconnect the source and clean up unnecessary items.
void m_cached_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
{
if (e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Add)
{
if (base.Count < MaxItems)
{
for (int i = 0; i < e.NewItems.Count; i++)
{
base.Add((T)e.NewItems[i]);
}
}
else
{
for (int i = base.Count – 1; i >= MaxItems; i–)
{
base.RemoveItem(i);
}
}
}
}
We should treat RemoveItem in order to be sure, that items, removed from cache will be removed from underlying data source as well (if they still there)
protected override void RemoveItem(int index)
{
T obj = base[index];
if(m_cached.Contains(obj))
m_cached.Remove(obj);
base.RemoveItem(index);
}
Actually, we finished. The only thing we should do it to interface MaxItem property and assure it to rise OnPropertyChanged event. ObservableCollection is not DependencyObject, thus we cannot use DependencyProperty there. INotifyPropertyChanged is still implemented.
int m_maxItems;
public int MaxItems
{
get { return m_maxItems; }
set { m_maxItems = value;
base.OnPropertyChanged(new PropertyChangedEventArgs(“MaxItems”));
}
}
Now, we can bind this property to Slider and manage maximum number of cached items by using binding.
Binding b1 = new Binding();
b1.Source = cache;
b1.Path = new PropertyPath(“MaxItems”);
sld.SetBinding(Slider.ValueProperty, b1);
Well done. However, I have another problem here. I need to enumerate ThreadSafeObservableColelction. Let’s see the code of MyData
ThreadPool.QueueUserWorkItem(delegate
{
while (true)
{
foreach (string str in this)
{
Log.Add(string.Format(“Inspecting {0}”, str));
if (Log.Count > 10)
Log.RemoveAt(0);
Thread.Sleep(100);
}}
});
If I’ll run it this way, I’ll get well known exception: Collection was modified; enumeration operation may not execute. This happens, because of rapidly changes in the collection, while enumerating it. We can use old well-known lock(SyncObj) method, however, we have no SyncObject in ObservableCollection<T>, thus we should provide thread safe read only disconnected array, that relays on original data in certain time period. We can continue write the collection, but we should be able to read, thus we’ll use ReaderLock to fix current collection state and create disconnected copy of items in this moment.
public T[] ToSyncArray()
{
_lock.AcquireReaderLock(-1);
T[] _sync = new T[this.Count];
this.CopyTo(_sync, 0);
_lock.ReleaseReaderLock();
return _sync;
}
Now, we finally done. We can read and write the collection, also we can have disconnected copy of it in order to provide consistent UI, while changing the actual data.
You may also be interested with:
- Real singleton approach in WPF application
- INotifyPropertyChanged auto wiring or how to get rid of redundant code
February 11th, 2008 · Comments (5)
5 Responses to “How to disconnect UI and Data in WPF (CachedObservableCollection) and some updates regarding ThreadSafeObservableCollection”
Leave a Reply
Discover other tags
My tools
- .NET Framework Detector
- Duplicate images finder
- Exchange Security Policy for Windows Mobile Devices Fix
- Gas Price Windows Vista SideBar gadget
- Israel Traffic Information Windows Vista SideBar gadget
- Localization fix for SAP ES Explorer for Visual Studio
- LocTester
- RTL and LTR in Windows Live Writer
- Silverlight controls library
- Snipping tool integration plugin for WLW
- USB FM receiver library
- Vista Battery Saver
- WebCam control for WPF
- Windows Live SkyDrive attachment for Windows Live Writer
- Wireless Migrator
- WPF Virtual Keyboard




January 1st, 2009 at 12:37 am
Pingback from blogs.microsoft.co.il/…/how-to-disconnect-ui-and-data-in-wpf-cachedobservablecollection-and-some-updates-regarding-threadsafeobservablecollection.aspx
January 1st, 2009 at 12:37 am
Hey Timir, great blog, read it lots.
I was just wondering, for the ThreadSafeObservableCollection, what are your thoughts on having a static constructor?
January 1st, 2009 at 12:37 am
Pingback from Reflective Perspective – Chris Alcock » The Morning Brew #32
January 1st, 2009 at 12:37 am
You’ve been kicked (a good thing) – Trackback from DotNetKicks.com
January 1st, 2009 at 12:37 am
Pingback from » Daily Bits – February 12, 2008 Alvin Ashcraft’s Daily Geek Bits: Daily links, development, gadgets and raising rugrats.