1+ using System ;
2+ using System . Collections ;
3+ using System . Collections . Generic ;
4+ using System . Collections . Immutable ;
5+ using System . Collections . Specialized ;
6+ using System . ComponentModel ;
7+ using System . Runtime . CompilerServices ;
8+ namespace DownKyi . ViewModels ;
9+
10+ public sealed class ImmutableObservableCollection < T > : IList < T > , IList , INotifyCollectionChanged , INotifyPropertyChanged
11+ {
12+ private ImmutableList < T > _items ;
13+
14+ public ImmutableObservableCollection ( )
15+ {
16+ _items = ImmutableList < T > . Empty ;
17+ }
18+
19+ public ImmutableObservableCollection ( IEnumerable < T > items )
20+ {
21+ _items = ImmutableList < T > . Empty . AddRange ( items ) ;
22+ }
23+
24+ public T this [ int index ]
25+ {
26+ get => _items [ index ] ;
27+ set
28+ {
29+ var oldItem = _items [ index ] ;
30+ _items = _items . SetItem ( index , value ) ;
31+ OnCollectionChanged ( new NotifyCollectionChangedEventArgs (
32+ NotifyCollectionChangedAction . Replace , value , oldItem , index ) ) ;
33+ }
34+ }
35+
36+ public int IndexOf ( T item ) => _items . IndexOf ( item ) ;
37+
38+ public void Insert ( int index , T item )
39+ {
40+ _items = _items . Insert ( index , item ) ;
41+ OnCollectionChanged ( new NotifyCollectionChangedEventArgs (
42+ NotifyCollectionChangedAction . Add , item , index ) ) ;
43+ OnPropertyChanged ( nameof ( Count ) ) ;
44+ }
45+
46+ public void Remove ( object ? value )
47+ {
48+ throw new NotImplementedException ( ) ;
49+ }
50+
51+ public void RemoveAt ( int index )
52+ {
53+ var removedItem = _items [ index ] ;
54+ _items = _items . RemoveAt ( index ) ;
55+ OnCollectionChanged ( new NotifyCollectionChangedEventArgs (
56+ NotifyCollectionChangedAction . Remove , removedItem , index ) ) ;
57+ OnPropertyChanged ( nameof ( Count ) ) ;
58+ }
59+
60+ public bool IsFixedSize => false ;
61+
62+ public void Add ( T item )
63+ {
64+ CheckReentrancy ( ) ;
65+ _items = _items . Add ( item ) ;
66+ OnCollectionChanged ( new NotifyCollectionChangedEventArgs (
67+ NotifyCollectionChangedAction . Add , item , _items . Count - 1 ) ) ;
68+ OnPropertyChanged ( nameof ( Count ) ) ;
69+ }
70+
71+ public bool Remove ( T item )
72+ {
73+ CheckReentrancy ( ) ;
74+ var index = _items . IndexOf ( item ) ;
75+ if ( index < 0 ) return false ;
76+
77+ _items = _items . Remove ( item ) ;
78+ OnCollectionChanged ( new NotifyCollectionChangedEventArgs (
79+ NotifyCollectionChangedAction . Remove , item , index ) ) ;
80+ OnPropertyChanged ( nameof ( Count ) ) ;
81+ return true ;
82+ }
83+
84+ public int Add ( object ? value )
85+ {
86+ #nullable disable
87+ T obj ;
88+ try
89+ {
90+ obj = ( T ) value ;
91+ }
92+ catch ( InvalidCastException ex )
93+ {
94+ throw new ArgumentException (
95+ $ "Value cannot be cast to type { typeof ( T ) . Name } .",
96+ nameof ( value ) , ex ) ;
97+ }
98+ this . Add ( obj ) ;
99+ return this . Count - 1 ;
100+ }
101+
102+ #nullable restore
103+
104+ public void Clear ( )
105+ {
106+ if ( _items . IsEmpty ) return ;
107+ CheckReentrancy ( ) ;
108+ _items = ImmutableList < T > . Empty ;
109+ OnCollectionChanged ( new NotifyCollectionChangedEventArgs (
110+ NotifyCollectionChangedAction . Reset ) ) ;
111+ OnPropertyChanged ( nameof ( Count ) ) ;
112+ }
113+
114+ public bool Contains ( object ? value )
115+ {
116+ throw new NotImplementedException ( ) ;
117+ }
118+
119+ public int IndexOf ( object ? value )
120+ {
121+ throw new NotImplementedException ( ) ;
122+ }
123+
124+ public void Insert ( int index , object ? value )
125+ {
126+ throw new NotImplementedException ( ) ;
127+ }
128+
129+ public bool Contains ( T item ) => _items . Contains ( item ) ;
130+ public void CopyTo ( T [ ] array , int arrayIndex ) => _items . CopyTo ( array , arrayIndex ) ;
131+ public void CopyTo ( Array array , int index )
132+ {
133+ throw new NotImplementedException ( ) ;
134+ }
135+
136+ public int Count => _items . Count ;
137+ public bool IsSynchronized => false ;
138+ public object SyncRoot => this ;
139+ public bool IsReadOnly => false ;
140+ object ? IList . this [ int index ]
141+ {
142+ get => this [ index ] ;
143+ set
144+ {
145+ #nullable disable
146+ T obj ;
147+ try
148+ {
149+ obj = ( T ) value ;
150+ }
151+ catch ( InvalidCastException ex )
152+ {
153+ throw new ArgumentException (
154+ $ "Value cannot be cast to type { typeof ( T ) . Name } .",
155+ nameof ( value ) , ex ) ;
156+ }
157+ this [ index ] = obj ;
158+ #nullable restore
159+ }
160+ }
161+
162+
163+ public IEnumerator < T > GetEnumerator ( ) => _items . GetEnumerator ( ) ;
164+ IEnumerator IEnumerable . GetEnumerator ( ) => _items . GetEnumerator ( ) ;
165+
166+ public event NotifyCollectionChangedEventHandler ? CollectionChanged ;
167+ public event PropertyChangedEventHandler ? PropertyChanged ;
168+
169+ private int _blockReentrancyCount ;
170+
171+ private void OnCollectionChanged ( NotifyCollectionChangedEventArgs e )
172+ {
173+ NotifyCollectionChangedEventHandler ? collectionChanged = this . CollectionChanged ;
174+ if ( collectionChanged == null )
175+ return ;
176+
177+ ++ this . _blockReentrancyCount ;
178+ try
179+ {
180+ collectionChanged ( this , e ) ;
181+ }
182+ finally
183+ {
184+ -- this . _blockReentrancyCount ;
185+ }
186+ }
187+
188+
189+ private void CheckReentrancy ( )
190+ {
191+ if ( this . _blockReentrancyCount <= 0 )
192+ return ;
193+ NotifyCollectionChangedEventHandler ? collectionChanged = this . CollectionChanged ;
194+ if ( collectionChanged != null && ! HasSingleTarget ( collectionChanged ) )
195+ {
196+ throw new InvalidOperationException ( "ObservableCollectionReentrancyNotAllowed" ) ;
197+ }
198+ }
199+
200+ private bool HasSingleTarget ( NotifyCollectionChangedEventHandler ? handler )
201+ {
202+ if ( handler == null )
203+ return true ;
204+
205+ return handler . GetInvocationList ( ) . Length <= 1 ;
206+ }
207+
208+ private void OnPropertyChanged ( [ CallerMemberName ] string ? propertyName = null )
209+ {
210+ PropertyChanged ? . Invoke ( this , new PropertyChangedEventArgs ( propertyName ) ) ;
211+ }
212+
213+ public void AddRange ( List < T > downloadingItems )
214+ {
215+ _items = _items . AddRange ( downloadingItems ) ;
216+ }
217+ }
0 commit comments