/Nova.AppFramework/ObservableCollectionExt.cs
http://coevery.codeplex.com · C# · 390 lines · 200 code · 40 blank · 150 comment · 7 complexity · b2984949f0292407b355d721b54b6534 MD5 · raw file
- using System;
- using System.Collections.Generic;
- using System.Collections.ObjectModel;
- using System.Collections.Specialized;
- using System.ComponentModel;
- using System.Linq;
- using System.Linq.Expressions;
- using System.Runtime.Serialization;
- using System.Text;
-
- namespace Nova.AppFramework
- {
- /// <summary>
- /// Extends <see cref = "INotifyPropertyChanged" /> such that the change event can be raised by external parties.
- /// </summary>
- public interface INotifyPropertyChangedEx : INotifyPropertyChanged
- {
- /// <summary>
- /// Enables/Disables property change notification.
- /// </summary>
- bool IsNotifying { get; set; }
-
- /// <summary>
- /// Notifies subscribers of the property change.
- /// </summary>
- /// <param name = "propertyName">Name of the property.</param>
- void NotifyOfPropertyChange(string propertyName);
-
- /// <summary>
- /// Raises a change notification indicating that all bindings should be refreshed.
- /// </summary>
- void Refresh();
- }
-
- [Serializable]
-
- /// <summary>
- /// A base class that implements the infrastructure for property change notification and automatically performs UI thread marshalling.
- /// </summary>
- public class PropertyChangedBase : INotifyPropertyChangedEx
- {
- /// <summary>
- /// Creates an instance of <see cref = "PropertyChangedBase" />.
- /// </summary>
- public PropertyChangedBase()
- {
- executor = new SafeExecutor(this);
- IsNotifying = true;
- }
-
- [field: NonSerialized]
- /// <summary>
- /// Occurs when a property value changes.
- /// </summary>
- public event PropertyChangedEventHandler PropertyChanged = delegate { };
-
- [field: NonSerialized]
- SafeExecutor executor;
-
- [field: NonSerialized]
- bool isNotifying; //serializator try to serialize even autogenerated fields
-
- /// <summary>
- /// Enables/Disables property change notification.
- /// </summary>
- public bool IsNotifying
- {
- get { return isNotifying; }
- set { isNotifying = value; }
- }
-
- /// <summary>
- /// Raises a change notification indicating that all bindings should be refreshed.
- /// </summary>
- public void Refresh()
- {
- NotifyOfPropertyChange(string.Empty);
- }
-
- /// <summary>
- /// Notifies subscribers of the property change.
- /// </summary>
- /// <param name = "propertyName">Name of the property.</param>
- public virtual void NotifyOfPropertyChange(string propertyName)
- {
- if (IsNotifying)
- executor.ExecuteOnUIThread(() => RaisePropertyChangedEventCore(propertyName));
- }
-
- /// <summary>
- /// Notifies subscribers of the property change.
- /// </summary>
- /// <typeparam name = "TProperty">The type of the property.</typeparam>
- /// <param name = "property">The property expression.</param>
- public virtual void NotifyOfPropertyChange<TProperty>(Expression<Func<TProperty>> property)
- {
- NotifyOfPropertyChange(property.GetMemberInfo().Name);
- }
-
- /// <summary>
- /// Raises the property changed event immediately.
- /// </summary>
- /// <param name = "propertyName">Name of the property.</param>
- public virtual void RaisePropertyChangedEventImmediately(string propertyName)
- {
- if (IsNotifying)
- RaisePropertyChangedEventCore(propertyName);
- }
-
- void RaisePropertyChangedEventCore(string propertyName)
- {
- var handler = PropertyChanged;
- if (handler != null)
- handler(this, new PropertyChangedEventArgs(propertyName));
- }
-
- [OnDeserialized]
- void OnDeserialized(StreamingContext c)
- {
- IsNotifying = true;
- }
- }
-
- /// <summary>
- /// Represents a collection that is observable.
- /// </summary>
- /// <typeparam name = "T">The type of elements contained in the collection.</typeparam>
- public interface IObservableCollection<T> : IList<T>, INotifyPropertyChangedEx, INotifyCollectionChanged
- {
- /// <summary>
- /// Adds the range.
- /// </summary>
- /// <param name = "items">The items.</param>
- void AddRange(IEnumerable<T> items);
-
- /// <summary>
- /// Removes the range.
- /// </summary>
- /// <param name = "items">The items.</param>
- void RemoveRange(IEnumerable<T> items);
- }
-
- /// <summary>
- /// A base collection class that supports automatic UI thread marshalling.
- /// </summary>
- /// <typeparam name="T">The type of elements contained in the collection.</typeparam>
- [Serializable]
- public class BindableCollection<T> : ObservableCollection<T>, IObservableCollection<T>
- {
- /// <summary>
- /// Initializes a new instance of the <see cref = "Illusion.BindableCollection{T}" /> class.
- /// </summary>
- public BindableCollection()
- {
- IsNotifying = true;
- executor = new SafeExecutor(this);
- }
-
- [field:NonSerialized]
- SafeExecutor executor;
-
- /// <summary>
- /// Initializes a new instance of the <see cref = "Illusion.BindableCollection{T}" /> class.
- /// </summary>
- /// <param name = "collection">The collection from which the elements are copied.</param>
- /// <exception cref = "T:System.ArgumentNullException">
- /// The <paramref name = "collection" /> parameter cannot be null.
- /// </exception>
- public BindableCollection(IEnumerable<T> collection)
- {
- IsNotifying = true;
- AddRange(collection);
- }
-
- [field: NonSerialized]
- bool isNotifying; //serializator try to serialize even autogenerated fields
-
- /// <summary>
- /// Enables/Disables property change notification.
- /// </summary>
- public bool IsNotifying
- {
- get { return isNotifying; }
- set { isNotifying = value; }
- }
-
- /// <summary>
- /// Notifies subscribers of the property change.
- /// </summary>
- /// <param name = "propertyName">Name of the property.</param>
- public void NotifyOfPropertyChange(string propertyName)
- {
- if (IsNotifying)
- executor.ExecuteOnUIThread(() => RaisePropertyChangedEventImmediately(new PropertyChangedEventArgs(propertyName)));
- }
-
- /// <summary>
- /// Raises a change notification indicating that all bindings should be refreshed.
- /// </summary>
- public void Refresh()
- {
- executor.ExecuteOnUIThread(() =>
- {
- OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
- OnPropertyChanged(new PropertyChangedEventArgs(string.Empty));
- });
- }
-
- /// <summary>
- /// Inserts the item to the specified position.
- /// </summary>
- /// <param name = "index">The index to insert at.</param>
- /// <param name = "item">The item to be inserted.</param>
- protected override sealed void InsertItem(int index, T item)
- {
- executor.ExecuteOnUIThread(() => InsertItemBase(index, item));
- }
-
- /// <summary>
- /// Exposes the base implementation of the <see cref = "InsertItem" /> function.
- /// </summary>
- /// <param name = "index">The index.</param>
- /// <param name = "item">The item.</param>
- /// <remarks>
- /// Used to avoid compiler warning regarding unverifiable code.
- /// </remarks>
- protected virtual void InsertItemBase(int index, T item)
- {
- base.InsertItem(index, item);
- }
-
- #if NET
- /// <summary>
- /// Moves the item within the collection.
- /// </summary>
- /// <param name="oldIndex">The old position of the item.</param>
- /// <param name="newIndex">The new position of the item.</param>
- protected sealed override void MoveItem(int oldIndex, int newIndex) {
- Execute.OnUIThread(() => MoveItemBase(oldIndex, newIndex));
- }
-
- /// <summary>
- /// Exposes the base implementation fo the <see cref="MoveItem"/> function.
- /// </summary>
- /// <param name="oldIndex">The old index.</param>
- /// <param name="newIndex">The new index.</param>
- /// <remarks>Used to avoid compiler warning regarding unverificable code.</remarks>
- protected virtual void MoveItemBase(int oldIndex, int newIndex) {
- base.MoveItem(oldIndex, newIndex);
- }
- #endif
-
- /// <summary>
- /// Sets the item at the specified position.
- /// </summary>
- /// <param name = "index">The index to set the item at.</param>
- /// <param name = "item">The item to set.</param>
- protected override sealed void SetItem(int index, T item)
- {
- executor.ExecuteOnUIThread(() => SetItemBase(index, item));
- }
-
- /// <summary>
- /// Exposes the base implementation of the <see cref = "SetItem" /> function.
- /// </summary>
- /// <param name = "index">The index.</param>
- /// <param name = "item">The item.</param>
- /// <remarks>
- /// Used to avoid compiler warning regarding unverifiable code.
- /// </remarks>
- protected virtual void SetItemBase(int index, T item)
- {
- base.SetItem(index, item);
- }
-
- /// <summary>
- /// Removes the item at the specified position.
- /// </summary>
- /// <param name = "index">The position used to identify the item to remove.</param>
- protected override sealed void RemoveItem(int index)
- {
- executor.ExecuteOnUIThread(() => RemoveItemBase(index));
- }
-
- /// <summary>
- /// Exposes the base implementation of the <see cref = "RemoveItem" /> function.
- /// </summary>
- /// <param name = "index">The index.</param>
- /// <remarks>
- /// Used to avoid compiler warning regarding unverifiable code.
- /// </remarks>
- protected virtual void RemoveItemBase(int index)
- {
- base.RemoveItem(index);
- }
-
- /// <summary>
- /// Clears the items contained by the collection.
- /// </summary>
- protected override sealed void ClearItems()
- {
- executor.ExecuteOnUIThread(ClearItemsBase);
- }
-
- /// <summary>
- /// Exposes the base implementation of the <see cref = "ClearItems" /> function.
- /// </summary>
- /// <remarks>
- /// Used to avoid compiler warning regarding unverifiable code.
- /// </remarks>
- protected virtual void ClearItemsBase()
- {
- base.ClearItems();
- }
-
- /// <summary>
- /// Raises the <see cref = "E:System.Collections.ObjectModel.ObservableCollection`1.CollectionChanged" /> event with the provided arguments.
- /// </summary>
- /// <param name = "e">Arguments of the event being raised.</param>
- protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
- {
- if (IsNotifying)
- base.OnCollectionChanged(e);
- }
-
- /// <summary>
- /// Raises the PropertyChanged event with the provided arguments.
- /// </summary>
- /// <param name = "e">The event data to report in the event.</param>
- protected override void OnPropertyChanged(PropertyChangedEventArgs e)
- {
- if (IsNotifying)
- base.OnPropertyChanged(e);
- }
-
- void RaisePropertyChangedEventImmediately(PropertyChangedEventArgs e)
- {
- OnPropertyChanged(e);
- }
-
- /// <summary>
- /// Adds the range.
- /// </summary>
- /// <param name = "items">The items.</param>
- public virtual void AddRange(IEnumerable<T> items)
- {
- executor.ExecuteOnUIThread(() =>
- {
- var previousNotificationSetting = IsNotifying;
- IsNotifying = false;
- var index = Count;
- foreach (var item in items)
- {
- InsertItemBase(index, item);
- index++;
- }
- IsNotifying = previousNotificationSetting;
- OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
- OnPropertyChanged(new PropertyChangedEventArgs(string.Empty));
- });
- }
-
- /// <summary>
- /// Removes the range.
- /// </summary>
- /// <param name = "items">The items.</param>
- public virtual void RemoveRange(IEnumerable<T> items)
- {
- executor.ExecuteOnUIThread(() =>
- {
- var previousNotificationSetting = IsNotifying;
- IsNotifying = false;
- foreach (var item in items)
- {
- var index = IndexOf(item);
- RemoveItemBase(index);
- }
- IsNotifying = previousNotificationSetting;
- OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
- OnPropertyChanged(new PropertyChangedEventArgs(string.Empty));
- });
- }
-
- [OnDeserialized]
- void OnDeserialized(StreamingContext c)
- {
- IsNotifying = true;
- }
- }
- }