UWP x:绑定到ObservableCollection时绑定更新,但不绑定到自定义INotifyCollectionChanged实现

时间:2017-04-12 03:06:44

标签: c# uwp observablecollection xbind

在我的UWP应用程序中有一个ListBox,列出最近使用的文件。我将该信息存储在ObservableCollection中,并将其绑定到ListBox的ItemsSource属性。更新按预期工作。

但是,如果我从ObservableCollection切换到SmartList(这是一个实现INotifyCollectionChanged的自定义列表),绑定将不再起作用。我经常在WPF应用程序中使用这个类,它总是运行良好。我还有测试CollecionChanged事件的单元测试。

在UpdateTriggers方面x:Bind和Binding之间是否存在差异,或者有人知道我在这里缺少什么?

//更新

以下是SmartList<T>的代码:

public class SmartList<T> : SmartCollectionBase<T>, IList<T>, INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    public override bool IsReadOnly => false;
    public override int Count => list.Count;

    private List<T> list;


    public SmartList()
    {
        list = new List<T>();
    }

    public SmartList(IEnumerable<T> collection)
    {
        list = new List<T>(collection);
    }

    public SmartList(int capacity)
    {
        list = new List<T>(capacity);
    }

    public override IEnumerator<T> GetEnumerator()
    {
        return list.GetEnumerator();
    }

    public override void Add(T item)
    {
        list.Add(item);
        OnItemsAdded(new SmartListChangedEventArgs(new SmartChange(item, list.Count - 1, ChangeType.Added)));
        NotifyCountChange();
    }

    public void AddRange(IEnumerable<T> items)
    {
        if (!items.Any())
            return;

        var changes = new List<SmartChange>();
        var idx = list.Count;
        foreach (var item in items)
        {
            list.Add(item);
            changes.Add(new SmartChange(item, idx, ChangeType.Added));
            idx++;
        }
        OnItemsAdded(new SmartListChangedEventArgs(changes));
        NotifyCountChange();
    }

    public void AddRange(params T[] items)
    {
        AddRange((IEnumerable<T>) items);
        NotifyCountChange();
    }

    public override void Clear()
    {
        if (list.Count == 0)
            return;

        var old = list;
        list = new List<T>(list.Capacity);
        OnItemsRemoved(new SmartListChangedEventArgs(old.Select((c, i) => new SmartChange(c, i, ChangeType.Removed))));
        NotifyCountChange();
    }

    public override bool Contains(T item)
    {
        return list.Contains(item);
    }

    public override void CopyTo(T[] array, int arrayIndex)
    {
        list.CopyTo(array, arrayIndex);
    }

    public override bool Remove(T item)
    {
        int idx = IndexOf(item);

        if (idx == -1)
            return false;

        RemoveAt(idx);
        NotifyCountChange();
        return true;
    }

    public int IndexOf(T item)
    {
        return list.IndexOf(item);
    }

    public void Insert(int index, T item)
    {
        list.Insert(index, item);
        OnItemsAdded(new SmartListChangedEventArgs(new SmartChange(item, index, ChangeType.Added)));
        NotifyCountChange();
    }

    public void InsertRange(int index, IEnumerable<T> items)
    {
        if (index > list.Count || index < 0)
            throw new IndexOutOfRangeException();

        if (!items.Any())
            return;

        var changes = items.Select((item, i) => new SmartChange(item, index + i, ChangeType.Added));
        list.InsertRange(index, items);

        OnItemsAdded(new SmartListChangedEventArgs(changes));
        NotifyCountChange();
    }

    public void InsertRange(int index, params T[] items)
    {
        InsertRange(index, (IEnumerable<T>) items);
        NotifyCountChange();
    }

    public void RemoveAt(int index)
    {
        var item = list[index];
        list.RemoveAt(index);
        OnItemsRemoved(new SmartListChangedEventArgs(new SmartChange(item, index, ChangeType.Removed)));
        NotifyCountChange();
    }

    public T this[int index]
    {
        get { return list[index]; }
        set
        {
            var old = list[index];
            if (ReferenceEquals(old, value))
                return;

            list[index] = value;
            OnItemsReplaced(new SmartListChangedEventArgs(new SmartChange(old, index, ChangeType.Removed), new SmartChange(value, index, ChangeType.Added)));
        }
    }

    protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }

    private void NotifyCountChange()
    {
        OnPropertyChanged(nameof(Count));
    }

及其基类:

public abstract class SmartCollectionBase<T> : ISmartCollection<T>
{
    public event NotifyCollectionChangedEventHandler CollectionChanged;
    public event EventHandler<SmartListChangedEventArgs> ItemsAdded;
    public event EventHandler<SmartListChangedEventArgs> ItemsRemoved;
    public event EventHandler<SmartListChangedEventArgs> ItemsMoved;
    public event EventHandler<SmartListChangedEventArgs> ItemsReplaced;
    public event EventHandler<SmartListChangedEventArgs> ItemsChanged;

    public abstract IEnumerator<T> GetEnumerator();
    public abstract void Add(T item);
    public abstract void Clear();
    public abstract bool Contains(T item);
    public abstract void CopyTo(T[] array, int arrayIndex);
    public abstract bool Remove(T item);
    public abstract int Count { get; }
    public abstract bool IsReadOnly { get; }


    IEnumerator IEnumerable.GetEnumerator()
    {
        return GetEnumerator();
    }

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

    protected virtual void OnItemsAdded(SmartListChangedEventArgs e)
    {
        ItemsAdded?.Invoke(this, e);
        OnItemsChanged(e);

        if (MustInvokeINotifyCollectionChanged())
            OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, e.Changes.Select(c => c.Change).ToList()));
    }

    protected virtual void OnItemsRemoved(SmartListChangedEventArgs e)
    {
        ItemsRemoved?.Invoke(this, e);
        OnItemsChanged(e);

        if (MustInvokeINotifyCollectionChanged())
            OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, e.Changes.Select(c => c.Change).ToList(), e.Changes[0].Index));
    }

    protected virtual void OnItemsMoved(SmartListChangedEventArgs e)
    {
        ItemsMoved?.Invoke(this, e);
        OnItemsChanged(e);

        if (MustInvokeINotifyCollectionChanged())
            OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Move, e.Changes.Select(c => c.Change).ToList(), e.Changes[0].Index, e.Changes[0].OldIndex));
    }

    protected virtual void OnItemsReplaced(SmartListChangedEventArgs e)
    {
        ItemsReplaced?.Invoke(this, e);
        OnItemsChanged(e);

        if (MustInvokeINotifyCollectionChanged())
        {
            var changes = e.Changes.GroupBy(c => c.ChangeType).OrderBy(g => g.Key).Select(g => g.ToList()).ToList();
            if (changes.Count != 2 || changes[0].Count != changes[1].Count)
                throw new InvalidOperationException("A replace operation must have an eqaul amount of added and removed items");
            OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Replace, changes[0], changes[1]));
        }
    }

    protected virtual void OnItemsChanged(SmartListChangedEventArgs e)
    {
        ItemsChanged?.Invoke(this, e);
    }

    private bool MustInvokeINotifyCollectionChanged()
    {
        return CollectionChanged != null;
    }

    public override string ToString()
    {
        return ToString(", ", "{0}");
    }

    public string ToString(string seperator, string format)
    {
        return this.Stringify(seperator, format);
    }
}

0 个答案:

没有答案