Feeling lazy part two

In my earlier post I talked about the lazy observable collection I created so that I could lazy load an observable collection so that I wasn't loading the entire collection until it was absolutely necessary. As a companion to that piece of work I also created a lazy read only observable collection. This brings the same features as the lazy observable collection except with advantage, depending on your viewpoint, of being read only.

using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.ComponentModel;

namespace Lazy
{
    /// <summary>
    /// represents a LazyReadOnlyCollection class that uses IQueryable for delayed loading and implements ICollection, INotifyCollectionChanged and INotifyPropertyChanged
    /// </summary>
    /// <typeparam name="T">the object type T</typeparam>
    public class LazyReadOnlyCollection<T> : ICollection<T>, INotifyCollectionChanged, INotifyPropertyChanged
    {
        #region members

        private readonly LazyCollection<T> _collection; 

        #endregion

        #region properties

        /// <summary>
        /// gets whether the collection has been loaded
        /// </summary>
        public bool HasLoaded
        {
            get { return _collection.HasLoaded; }
        }

        /// <summary>
        /// gets the item from the list at the specified index
        /// </summary>
        /// <param name="index">the index of the item in the list</param>
        /// <returns>the item</returns>
        public T this[int index]
        {
            get
            {
                return _collection[index];
            }
        }

        #endregion

        #region constructors

        /// <summary>
        /// default constructor
        /// </summary>
        /// <param name="collection">a LazyCollection of type T</param>
        public LazyReadOnlyCollection(LazyCollection<T> collection)
        {
            //set properties
            _collection = collection;

            //subscribe to events
            _collection.CollectionChanged += HandleCollectionChanged;
            _collection.PropertyChanged += HandlePropertyChanged;
        }

        #endregion

        #region methods

        #endregion

        #region ICollection<T> Members

        /// <summary>
        /// adds the item to the collection
        /// </summary>
        /// <param name="item">the item to add</param>
        public void Add(T item)
        {
            throw new NotImplementedException("The collection is read only");
        }

        /// <summary>
        /// clears the collection
        /// </summary>
        public void Clear()
        {
            throw new NotImplementedException("The collection is read only");
        }

        /// <summary>
        /// determines whether the item is contained within the collection
        /// </summary>
        /// <param name="item">the item to find</param>
        /// <returns>a boolean value indicating whether the item was found</returns>
        public bool Contains(T item)
        {
            return _collection.Contains(item);
        }

        /// <summary>
        /// copies the collection to an array starting at the specified index
        /// </summary>
        /// <param name="array">the target array</param>
        /// <param name="arrayIndex">the starting index</param>
        public void CopyTo(T[] array, int arrayIndex)
        {
            _collection.CopyTo(array, arrayIndex);
        }

        /// <summary>
        /// gets the number of items in the collection
        /// </summary>
        public int Count
        {
            get { return _collection.Count; }
        }

        /// <summary>
        /// determines whether the collection is read only
        /// </summary>
        public bool IsReadOnly
        {
            get { return true; }
        }

        /// <summary>
        /// removes the item from the collection
        /// </summary>
        /// <param name="item">the item to remove</param>
        /// <returns>a boolean value indicating whether the item was removed</returns>
        public bool Remove(T item)
        {
            throw new NotImplementedException("The collection is read only");
        }

        #endregion

        #region IEnumerable<T> Members

        /// <summary>
        /// gets the enumerator to iterate over the collection
        /// </summary>
        /// <returns>IEnumerator</returns>
        public IEnumerator<T> GetEnumerator()
        {
            return _collection.GetEnumerator();
        }

        #endregion

        #region IEnumerable Members

        /// <summary>
        /// gets the enumerator to iterate over the collection
        /// </summary>
        /// <returns>IEnumerator</returns>
        IEnumerator IEnumerable.GetEnumerator()
        {
            return _collection.GetEnumerator();
        }

        #endregion

        #region INotifyCollectionChanged Members

        /// <summary>
        /// CollectionChanged event
        /// </summary>
        public event NotifyCollectionChangedEventHandler CollectionChanged;

        /// <summary>
        /// handles the collection changed events of the inner collection and forwards them on
        /// </summary>
        /// <param name="sender">the object that raised the event</param>
        /// <param name="e">NotifyCollectionChangedEventArgs</param>
        void HandleCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
        {
            OnCollectionChanged(e);
        }

        /// <summary>
        /// raises the CollectionChanged event
        /// </summary>
        /// <param name="e">NotifyCollectionChangedEventArgs</param>
        protected virtual void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
        {
            if (CollectionChanged != null)
            {
                CollectionChanged(this, e);   
            }
        }

        #endregion

        #region INotifyPropertyChanged Members

        /// <summary>
        /// PropertyChanged event
        /// </summary>
        public event PropertyChangedEventHandler PropertyChanged;

        /// <summary>
        /// handles the property changed events from the inner collection and forwards them on
        /// </summary>
        /// <param name="sender">the object that raised the event</param>
        /// <param name="e">PropertyChangedEventArgs</param>
        void HandlePropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            OnPropertyChanged(e);
        }

        /// <summary>
        /// raises the PropertyChanged event
        /// </summary>
        /// <param name="e">PropertyChangedEventArgs</param>
        protected virtual void OnPropertyChanged(PropertyChangedEventArgs e)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, e);
            }
        }

        #endregion

        #region Monitor

        /// <summary>
        /// represents a Monitor class that implements IDisposable
        /// </summary>
        /// <remarks>used to prevent reentrant calls</remarks>
        private class Monitor : IDisposable
        {
            #region members

            private int _busyCount;

            #endregion

            #region properties

            /// <summary>
            /// gets the busy state
            /// </summary>
            public bool Busy
            {
                get { return _busyCount > 0; }
            }

            #endregion

            #region constructors

            /// <summary>
            /// default constructor
            /// </summary>
            public Monitor()
            {

            }

            #endregion

            #region methods

            /// <summary>
            /// increments the busy count
            /// </summary>
            public void Enter()
            {
                ++_busyCount;
            }

            #endregion

            #region IDisposable Members

            /// <summary>
            /// decrements the busy count
            /// </summary>
            public void Dispose()
            {
                --_busyCount;
            }

            #endregion
        }

        #endregion
    }
}

0 Comments

Add a Comment