namespace Caliburn.Micro.Core { using System.Collections.Generic; using System.Collections.ObjectModel; using System.Collections.Specialized; using System.ComponentModel; /// /// A base collection class that supports automatic UI thread marshalling. /// /// The type of elements contained in the collection. public class BindableCollection : ObservableCollection, IObservableCollection { /// /// Initializes a new instance of the class. /// public BindableCollection() { IsNotifying = true; } /// /// Initializes a new instance of the class. /// /// The collection from which the elements are copied. public BindableCollection(IEnumerable collection) : base(collection) { IsNotifying = true; } /// /// Enables/Disables property change notification. /// public bool IsNotifying { get; set; } /// /// Notifies subscribers of the property change. /// /// Name of the property. public virtual void NotifyOfPropertyChange(string propertyName) { if (IsNotifying) Execute.OnUIThread(() => OnPropertyChanged(new PropertyChangedEventArgs(propertyName))); } /// /// Raises a change notification indicating that all bindings should be refreshed. /// public void Refresh() { Execute.OnUIThread(() => { OnPropertyChanged(new PropertyChangedEventArgs("Count")); OnPropertyChanged(new PropertyChangedEventArgs("Item[]")); OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset)); }); } /// /// Inserts the item to the specified position. /// /// The index to insert at. /// The item to be inserted. protected override sealed void InsertItem(int index, T item) { Execute.OnUIThread(() => InsertItemBase(index, item)); } /// /// Exposes the base implementation of the function. /// /// The index. /// The item. /// /// Used to avoid compiler warning regarding unverifiable code. /// protected virtual void InsertItemBase(int index, T item) { base.InsertItem(index, item); } /// /// Sets the item at the specified position. /// /// The index to set the item at. /// The item to set. protected override sealed void SetItem(int index, T item) { Execute.OnUIThread(() => SetItemBase(index, item)); } /// /// Exposes the base implementation of the function. /// /// The index. /// The item. /// /// Used to avoid compiler warning regarding unverifiable code. /// protected virtual void SetItemBase(int index, T item) { base.SetItem(index, item); } /// /// Removes the item at the specified position. /// /// The position used to identify the item to remove. protected override sealed void RemoveItem(int index) { Execute.OnUIThread(() => RemoveItemBase(index)); } /// /// Exposes the base implementation of the function. /// /// The index. /// /// Used to avoid compiler warning regarding unverifiable code. /// protected virtual void RemoveItemBase(int index) { base.RemoveItem(index); } /// /// Clears the items contained by the collection. /// protected override sealed void ClearItems() { Execute.OnUIThread(ClearItemsBase); } /// /// Exposes the base implementation of the function. /// /// /// Used to avoid compiler warning regarding unverifiable code. /// protected virtual void ClearItemsBase() { base.ClearItems(); } /// /// Raises the event with the provided arguments. /// /// Arguments of the event being raised. protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e) { if (IsNotifying) { base.OnCollectionChanged(e); } } /// /// Raises the PropertyChanged event with the provided arguments. /// /// The event data to report in the event. protected override void OnPropertyChanged(PropertyChangedEventArgs e) { if (IsNotifying) { base.OnPropertyChanged(e); } } /// /// Adds the range. /// /// The items. public virtual void AddRange(IEnumerable items) { Execute.OnUIThread(() => { var previousNotificationSetting = IsNotifying; IsNotifying = false; var index = Count; foreach (var item in items) { InsertItemBase(index, item); index++; } IsNotifying = previousNotificationSetting; OnPropertyChanged(new PropertyChangedEventArgs("Count")); OnPropertyChanged(new PropertyChangedEventArgs("Item[]")); OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset)); }); } /// /// Removes the range. /// /// The items. public virtual void RemoveRange(IEnumerable items) { Execute.OnUIThread(() => { var previousNotificationSetting = IsNotifying; IsNotifying = false; foreach (var item in items) { var index = IndexOf(item); if (index >= 0) { RemoveItemBase(index); } } IsNotifying = previousNotificationSetting; OnPropertyChanged(new PropertyChangedEventArgs("Count")); OnPropertyChanged(new PropertyChangedEventArgs("Item[]")); OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset)); }); } } }