There's nothing special about the ObservableCollection
other than it implements INotifyCollectionChanged
and INotifyPropertyChanged
.
I suggests that you create your own ObservableCollection
with the required behavior.
Public Class ObservableStack(Of T)
Implements IEnumerable, ICollection, IList
Implements IEnumerable(Of T), ICollection(Of T), IList(Of T)
Implements INotifyCollectionChanged, INotifyPropertyChanged
Public Sub New()
Me.list = New List(Of T)
End Sub
'...
Public Sub Add(item As T) Implements ICollection(Of T).Add
'TODO: Validate.
Me.list.Insert(0, item) 'Insert at top of the list.
Me.RaisePropertyChanged("Count")
Me.RaisePropertyChanged("Item")
Me.RaiseCollectionChanged(NotifyCollectionChangedAction.Add, item, 0)
End Sub
Private Function _Add(obj As Object) As Integer Implements IList.Add
Me.Add(TryCast(obj, T))
Return 0
End Function
'...
Private ReadOnly list As List(Of T)
End Class
Example
Public Class ObservableStack(Of T)
Implements IEnumerable, ICollection, IList
Implements IEnumerable(Of T), ICollection(Of T), IList(Of T)
Implements INotifyCollectionChanged, INotifyPropertyChanged
Public Sub New()
Me.list = New List(Of T)
End Sub
Public Event CollectionChanged As NotifyCollectionChangedEventHandler Implements INotifyCollectionChanged.CollectionChanged
Protected Event PropertyChanged As PropertyChangedEventHandler Implements INotifyPropertyChanged.PropertyChanged
Public ReadOnly Property Count() As Integer Implements ICollection.Count, ICollection(Of T).Count
Get
Return Me.list.Count
End Get
End Property
Default Public Property Item(index As Integer) As T Implements IList(Of T).Item
Get
Return Me.list.Item(index)
End Get
Set(value As T)
Me.Replace(index, value)
End Set
End Property
Private ReadOnly Property _IsFixedSize() As Boolean Implements IList.IsFixedSize
Get
Return CType(Me.list, IList).IsFixedSize
End Get
End Property
Private ReadOnly Property _IsReadOnly() As Boolean Implements IList.IsReadOnly, ICollection(Of T).IsReadOnly
Get
Return CType(Me.list, IList).IsReadOnly
End Get
End Property
Private ReadOnly Property _IsSynchronized() As Boolean Implements ICollection.IsSynchronized
Get
Return CType(Me.list, ICollection).IsSynchronized
End Get
End Property
Private Property _Item(index As Integer) As Object Implements IList.Item
Get
Return Me.Item(index)
End Get
Set(value As Object)
Me.Item(index) = DirectCast(value, T)
End Set
End Property
Private ReadOnly Property _SyncRoot() As Object Implements ICollection.SyncRoot
Get
Return CType(Me.list, ICollection).SyncRoot
End Get
End Property
Public Sub Add(item As T) Implements ICollection(Of T).Add
Me.Insert(0, item)
End Sub
Public Sub Clear() Implements IList.Clear, ICollection(Of T).Clear
If (Me.Count > 0) Then
Me.list.Clear()
Me.RaisePropertyChanged("Count")
Me.RaisePropertyChanged("Item")
Me.RaiseCollectionReset()
End If
End Sub
Public Function Contains(item As T) As Boolean Implements ICollection(Of T).Contains
Return Me.list.Contains(item)
End Function
Public Sub CopyTo(array() As T, index As Integer) Implements ICollection(Of T).CopyTo
Me.list.CopyTo(array, index)
End Sub
Public Function GetEnumerator() As IEnumerator(Of T) Implements IEnumerable(Of T).GetEnumerator
Return Me.list.GetEnumerator()
End Function
Public Function IndexOf(item As T) As Integer Implements IList(Of T).IndexOf
Return Me.list.IndexOf(item)
End Function
Public Sub Insert(index As Integer, item As T) Implements IList(Of T).Insert
'TODO: Validate item.
Me.list.Insert(index, item)
Me.RaisePropertyChanged("Count")
Me.RaisePropertyChanged("Item")
Me.RaiseCollectionChanged(NotifyCollectionChangedAction.Add, item, index)
End Sub
Public Sub Move(ByVal oldIndex As Integer, ByVal newIndex As Integer)
Me.MoveItem(oldIndex, newIndex)
End Sub
Protected Overridable Sub MoveItem(ByVal oldIndex As Integer, ByVal newIndex As Integer)
Dim item As T = Me.Item(oldIndex)
Me.list.RemoveAt(oldIndex)
Me.list.Insert(newIndex, item)
Me.RaisePropertyChanged("Item")
Me.RaiseCollectionChanged(NotifyCollectionChangedAction.Move, item, newIndex, oldIndex)
End Sub
Protected Overridable Sub OnCollectionChanged(e As NotifyCollectionChangedEventArgs)
RaiseEvent CollectionChanged(Me, e)
End Sub
Protected Overridable Sub OnPropertyChanged(e As PropertyChangedEventArgs)
RaiseEvent PropertyChanged(Me, e)
End Sub
Private Sub RaiseCollectionChanged(action As NotifyCollectionChangedAction, item As T, index As Integer)
Me.OnCollectionChanged(New NotifyCollectionChangedEventArgs(action, item, index))
End Sub
Private Sub RaiseCollectionChanged(ByVal action As NotifyCollectionChangedAction, ByVal item As Object, ByVal index As Integer, ByVal oldIndex As Integer)
Me.OnCollectionChanged(New NotifyCollectionChangedEventArgs(action, item, index, oldIndex))
End Sub
Private Sub RaiseCollectionChanged(action As NotifyCollectionChangedAction, oldItem As T, newItem As T, index As Integer)
Me.OnCollectionChanged(New NotifyCollectionChangedEventArgs(action, newItem, oldItem, index))
End Sub
Private Sub RaiseCollectionReset()
Me.OnCollectionChanged(New NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset))
End Sub
Private Sub RaisePropertyChanged(propertyName As String)
Me.OnPropertyChanged(New PropertyChangedEventArgs(propertyName))
End Sub
Public Function Remove(item As T) As Boolean Implements ICollection(Of T).Remove
Dim index As Integer = Me.IndexOf(item)
If (index <> -1) Then
Me.RemoveAt(index)
Return True
End If
Return False
End Function
Public Sub RemoveAt(index As Integer) Implements IList.RemoveAt, IList(Of T).RemoveAt
Dim item As T = Me.Item(index)
Me.list.RemoveAt(index)
Me.RaisePropertyChanged("Count")
Me.RaisePropertyChanged("Item")
Me.RaiseCollectionChanged(NotifyCollectionChangedAction.Remove, item, index)
End Sub
Public Sub Replace(index As Integer, newItem As T)
'TODO: Validate item.
Dim oldItem As T = Me.Item(index)
Me.list.Item(index) = newItem
Me.RaisePropertyChanged("Item")
Me.RaiseCollectionChanged(NotifyCollectionChangedAction.Replace, oldItem, newItem, index)
End Sub
Private Function _Add(obj As Object) As Integer Implements IList.Add
Me.Add(DirectCast(obj, T))
Return 0
End Function
Private Function _Contains(obj As Object) As Boolean Implements IList.Contains
Return Me.Contains(DirectCast(obj, T))
End Function
Private Sub _CopyTo(array As Array, index As Integer) Implements ICollection.CopyTo
CType(Me.list, ICollection).CopyTo(array, index)
End Sub
Private Function _GetEnumerator() As IEnumerator Implements IEnumerable.GetEnumerator
Return Me.GetEnumerator()
End Function
Private Function _IndexOf(obj As Object) As Integer Implements IList.IndexOf
Return Me.IndexOf(DirectCast(obj, T))
End Function
Private Sub _Insert(index As Integer, obj As Object) Implements IList.Insert
Me.Insert(index, DirectCast(obj, T))
End Sub
Private Sub _Remove(obj As Object) Implements IList.Remove
Me.Remove(DirectCast(obj, T))
End Sub
Private ReadOnly list As List(Of T)
End Class