Search code examples
c#wpfxamldata-bindinguwp

Issue with ObservableStack<T> implementation and XAML Binding


Where have I gone wrong with my implementation of a ObservableStack<T>? The XAML is failing to bind to it some how and so the information contained in the stack is not showing in the UI. If I only change the type of the property in the ViewModel from my ObservableStack<T> to ObservableCollection<T> then the UI elements appear. This makes me think it's the implementation.

I want to use this so my elements appear in the UI in Stack order and not collection order.

Here is my implementation:

public class ObservableStack<T> :  INotifyPropertyChanged, INotifyCollectionChanged, ICollection , IEnumerable<T>, IEnumerable , IReadOnlyCollection<T>
{
    ObservableCollection<T> _coll = new ObservableCollection<T>();

    public ObservableStack()
    {
        _coll.CollectionChanged += _coll_CollectionChanged;
    }

    public ObservableStack(IEnumerable<T> items) : base()
    {
        foreach (var item in items)
        {
            Push(item);
        }
    }

    private void _coll_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
    {
        OnCollectionChanged(e);
    }

    public void Push(T item)
    {
        _coll.Insert(0, item);
    }

    public void Pop()
    {
        _coll.RemoveAt(0);
    }

    public T Peek
    {
        get { return _coll[0]; }
    }

    public int Count
    {
        get
        {
            return ((ICollection)_coll).Count;
        }
    }

    public bool IsSynchronized
    {
        get
        {
            return ((ICollection)_coll).IsSynchronized;
        }
    }

    public object SyncRoot
    {
        get
        {
            return ((ICollection)_coll).SyncRoot;
        }
    }

    public void CopyTo(Array array, int index)
    {
        ((ICollection)_coll).CopyTo(array, index);
    }

    public IEnumerator GetEnumerator()
    {
        return ((ICollection)_coll).GetEnumerator();
    }

    IEnumerator<T> IEnumerable<T>.GetEnumerator()
    {
        return ((IEnumerable<T>)_coll).GetEnumerator();
    }

    #region INotifyPropertyChanged
    protected void OnPropertyChanged([CallerMemberName] string caller = "")
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(caller));
    }

    public event PropertyChangedEventHandler PropertyChanged;
    #endregion

    #region INotifyCollectionChanged
    public event NotifyCollectionChangedEventHandler CollectionChanged;

    protected void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
    {
        CollectionChanged?.Invoke(this, e);
    }
    #endregion

}

Solution

  • The solution I've found is that I needed to implement IList on my ObservableStack. After that everything worked as expected. Curiously, just implementing IList<T> didn't work. It needed the non generic interface. Thanks again to those who offered help.