Platform: WPF, .NET 4.0, C# 4.0
Problem: In the Mainwindow.xaml i have a ListBox bound to a Customer collection which is currently an ObservableCollecti
Please take a look at the BindableCollection from Caliburn.Micro library:
///
/// A base collection class that supports automatic UI thread marshalling.
///
/// The type of elements contained in the collection.
#if !SILVERLIGHT && !WinRT
[Serializable]
#endif
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.
///
/// The parameter cannot be null.
///
public BindableCollection(IEnumerable collection) : base(collection) {
IsNotifying = true;
}
#if !SILVERLIGHT && !WinRT
[field: NonSerialized]
#endif
bool isNotifying; //serializator try to serialize even autogenerated fields
///
/// Enables/Disables property change notification.
///
#if !WinRT
[Browsable(false)]
#endif
public bool IsNotifying {
get { return isNotifying; }
set { isNotifying = value; }
}
///
/// Notifies subscribers of the property change.
///
/// Name of the property.
#if WinRT || NET45
public virtual void NotifyOfPropertyChange([CallerMemberName]string propertyName = "") {
#else
public virtual void NotifyOfPropertyChange(string propertyName) {
#endif
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);
}
#if NET || WP8 || WinRT
///
/// Moves the item within the collection.
///
/// The old position of the item.
/// The new position of the item.
protected sealed override void MoveItem(int oldIndex, int newIndex) {
Execute.OnUIThread(() => MoveItemBase(oldIndex, newIndex));
}
///
/// Exposes the base implementation fo the function.
///
/// The old index.
/// The new index.
/// Used to avoid compiler warning regarding unverificable code.
protected virtual void MoveItemBase(int oldIndex, int newIndex) {
base.MoveItem(oldIndex, newIndex);
}
#endif
///
/// 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));
});
}
///
/// Called when the object is deserialized.
///
/// The streaming context.
[OnDeserialized]
public void OnDeserialized(StreamingContext c) {
IsNotifying = true;
}
///
/// Used to indicate whether or not the IsNotifying property is serialized to Xml.
///
/// Whether or not to serialize the IsNotifying property. The default is false.
public virtual bool ShouldSerializeIsNotifying() {
return false;
}
}
Source
PS. Just take in mind that this class use some other classes from Caliburn.Micro so that you could either copy/pase all dependencies by your-self - OR - if you are not using any other application frameworks - just reference the library binary and give it a chance.