bring back CodeContracts to mobile profiles.
[mono-project.git] / mcs / class / System / System.Collections.ObjectModel / ObservableCollection.cs
blob7f3f812ed6f64bea6350fdd348b5bbe57dbddfdd
1 // Permission is hereby granted, free of charge, to any person obtaining
2 // a copy of this software and associated documentation files (the
3 // "Software"), to deal in the Software without restriction, including
4 // without limitation the rights to use, copy, modify, merge, publish,
5 // distribute, sublicense, and/or sell copies of the Software, and to
6 // permit persons to whom the Software is furnished to do so, subject to
7 // the following conditions:
8 //
9 // The above copyright notice and this permission notice shall be
10 // included in all copies or substantial portions of the Software.
11 //
12 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
13 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
14 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
15 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
16 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
17 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
18 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20 // Copyright (c) 2007 Novell, Inc. (http://www.novell.com)
21 // Copyright 2011 Xamarin Inc.
23 // Authors:
24 // Chris Toshok (toshok@novell.com)
25 // Brian O'Keefe (zer0keefie@gmail.com)
26 // Marek Safar (marek.safar@gmail.com)
29 #if NET_4_0 || MOBILE
30 using System.Collections.Generic;
31 using System.Collections.Specialized;
32 using System.ComponentModel;
33 using System.Runtime.CompilerServices;
35 namespace System.Collections.ObjectModel
37 [Serializable]
38 #if !MOBILE
39 [TypeForwardedFrom (Consts.WindowsBase_3_0)]
40 #endif
41 public class ObservableCollection<T> : Collection<T>, INotifyCollectionChanged, INotifyPropertyChanged {
43 private class Reentrant : IDisposable {
44 private int count = 0;
46 public Reentrant()
50 public void Enter()
52 count++;
55 public void Dispose()
57 count--;
60 public bool Busy
62 get { return count > 0; }
66 private Reentrant reentrant = new Reentrant ();
68 public ObservableCollection ()
72 public ObservableCollection (IEnumerable<T> collection)
74 if (collection == null)
75 throw new ArgumentNullException ("collection");
77 foreach (var item in collection)
78 Add (item);
81 public ObservableCollection (List<T> list)
82 : base (list != null ? new List<T> (list) : null)
86 public virtual event NotifyCollectionChangedEventHandler CollectionChanged;
87 protected virtual event PropertyChangedEventHandler PropertyChanged;
89 event PropertyChangedEventHandler INotifyPropertyChanged.PropertyChanged {
90 add { this.PropertyChanged += value; }
91 remove { this.PropertyChanged -= value; }
94 protected IDisposable BlockReentrancy ()
96 reentrant.Enter ();
97 return reentrant;
100 protected void CheckReentrancy ()
102 NotifyCollectionChangedEventHandler eh = CollectionChanged;
104 // Only have a problem if we have more than one event listener.
105 if (reentrant.Busy && eh != null && eh.GetInvocationList ().Length > 1)
106 throw new InvalidOperationException ("Cannot modify the collection while reentrancy is blocked.");
109 protected override void ClearItems ()
111 CheckReentrancy ();
113 base.ClearItems ();
115 OnCollectionChanged (new NotifyCollectionChangedEventArgs (NotifyCollectionChangedAction.Reset));
116 OnPropertyChanged (new PropertyChangedEventArgs ("Count"));
117 OnPropertyChanged (new PropertyChangedEventArgs ("Item[]"));
120 protected override void InsertItem (int index, T item)
122 CheckReentrancy ();
124 base.InsertItem (index, item);
126 OnCollectionChanged (new NotifyCollectionChangedEventArgs (NotifyCollectionChangedAction.Add, item, index));
127 OnPropertyChanged (new PropertyChangedEventArgs ("Count"));
128 OnPropertyChanged (new PropertyChangedEventArgs ("Item[]"));
131 public void Move (int oldIndex, int newIndex)
133 MoveItem (oldIndex, newIndex);
136 protected virtual void MoveItem (int oldIndex, int newIndex)
138 CheckReentrancy ();
140 T item = Items [oldIndex];
141 base.RemoveItem (oldIndex);
142 base.InsertItem (newIndex, item);
144 OnCollectionChanged (new NotifyCollectionChangedEventArgs (NotifyCollectionChangedAction.Move, item, newIndex, oldIndex));
145 OnPropertyChanged (new PropertyChangedEventArgs ("Item[]"));
148 protected virtual void OnCollectionChanged (NotifyCollectionChangedEventArgs e)
150 NotifyCollectionChangedEventHandler eh = CollectionChanged;
152 if (eh != null) {
153 // Make sure that the invocation is done before the collection changes,
154 // Otherwise there's a chance of data corruption.
155 using (BlockReentrancy ()) {
156 eh (this, e);
161 protected virtual void OnPropertyChanged (PropertyChangedEventArgs e)
163 PropertyChangedEventHandler eh = PropertyChanged;
165 if (eh != null)
166 eh (this, e);
169 protected override void RemoveItem (int index)
171 CheckReentrancy ();
173 T item = Items [index];
175 base.RemoveItem (index);
177 OnCollectionChanged (new NotifyCollectionChangedEventArgs (NotifyCollectionChangedAction.Remove, item, index));
178 OnPropertyChanged (new PropertyChangedEventArgs ("Count"));
179 OnPropertyChanged (new PropertyChangedEventArgs ("Item[]"));
182 protected override void SetItem (int index, T item)
184 CheckReentrancy ();
186 T oldItem = Items [index];
188 base.SetItem (index, item);
190 OnCollectionChanged (new NotifyCollectionChangedEventArgs (NotifyCollectionChangedAction.Replace, item, oldItem, index));
191 OnPropertyChanged (new PropertyChangedEventArgs ("Item[]"));
195 #endif