C# 为UWP调整AsyncObservableCollection后出现奇怪的生成异常

C# 为UWP调整AsyncObservableCollection后出现奇怪的生成异常,c#,asynchronous,win-universal-app,C#,Asynchronous,Win Universal App,我已尝试将来自的异步集合改编为UWP。但是如果我尝试构建文件,我会收到以下错误: 严重性代码说明项目文件行抑制状态 错误无法确定集合类型'Logic.Model.AsyncObservableCollection'1[DataAccess.Core.ch.Phex.API.Customer]'的项类型,因为它有多个Add方法或ICollection实现。要使此集合类型在XAML中可用,请添加公共添加(对象)方法、实现System.Collections.IList或单个System.Collec

我已尝试将来自的异步集合改编为UWP。但是如果我尝试构建文件,我会收到以下错误:

严重性代码说明项目文件行抑制状态 错误无法确定集合类型'Logic.Model.AsyncObservableCollection'1[DataAccess.Core.ch.Phex.API.Customer]'的项类型,因为它有多个Add方法或ICollection实现。要使此集合类型在XAML中可用,请添加公共添加(对象)方法、实现System.Collections.IList或单个System.Collections.Generic.ICollection。Ui.Windows

谁能给我一个提示吗

致意 卡菲

源代码

    public delegate void OnMtCollectionChangedHandler(object sender, NotifyCollectionChangedEventArgs args);
[DataContract]
public  class AsyncObservableCollection<T> : ICollection<T>, IReadOnlyList<T>
{
    // ******************************************************************
    private List<T> _recordedNew = new List<T>();
    private List<T> _recordedRemoved = new List<T>();
    private bool _isRecording = false;

    private readonly object _syncRoot = new object();
    protected List<T> List = new List<T>();
    private readonly ObservableCollection<T> _obsColl = new ObservableCollection<T>();
    private readonly ConcurrentQueue<NotifyCollectionChangedEventArgs> _uiItemQueue = new ConcurrentQueue<NotifyCollectionChangedEventArgs>();
    public event OnMtCollectionChangedHandler OnMtCollectionChanged;
    public CoreDispatcher Dispatcher { get; set; }

    // ******************************************************************
    /// <summary>
    /// You should never add any item directly in the collection. 
    /// It should only serve as a readonly collection for the UI.
    /// If you ever decide to do so, it would be preferable to use directly the ObsCollection 
    /// without ever using this class (kind of detach)
    /// </summary>
    public ObservableCollection<T> ObsColl
    {
        get { return _obsColl; }
    }

    // ******************************************************************
    public AsyncObservableCollection()
    {
        //Dispatcher = Application.Current;
        Dispatcher = Window.Current.Dispatcher;
    }


    public AsyncObservableCollection(Collection<T> collection)
    {
        //Dispatcher = Application.Current;
        Dispatcher = Window.Current.Dispatcher;
        this.Add(collection.ToList<T>());
    }




    // ******************************************************************
    public bool IsRecording
    {
        get { return _isRecording; }
        set { _isRecording = value; }
    }

    // ******************************************************************
    /// <summary>
    /// Return tuple of new and removed items
    /// </summary>
    /// <returns></returns>
    public Tuple<List<T>, List<T>> ResetRecordedItems()
    {
        Tuple<List<T>, List<T>> changes;
        lock (_syncRoot)
        {
            changes = new Tuple<List<T>, List<T>>(_recordedNew, _recordedRemoved);
            _recordedNew = new List<T>();
            _recordedRemoved = new List<T>();
        }

        return changes;
    }

    // ******************************************************************
    public T[] GetCopyOfRecordedItemsNew()
    {
        T[] changes;
        lock (_syncRoot)
        {
            changes = _recordedNew.ToArray();
        }

        return changes;
    }

    // ******************************************************************
    public T[] GetCopyOfRecordedItemsRemoved()
    {
        T[] changes;
        lock (_syncRoot)
        {
            changes = _recordedRemoved.ToArray();
        }

        return changes;
    }

    // ******************************************************************
    private async void AddTask(NotifyCollectionChangedEventArgs args)
    {
        _uiItemQueue.Enqueue(args);
        // Dispatcher.BeginInvoke(new Action(this.ProcessQueue));
        await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
             {
                 this.ProcessQueue();
             });
    }

    // ******************************************************************
    private void ProcessQueue()
    {
        // This Method should always be invoked only by the UI thread only.
        if (!this.Dispatcher.HasThreadAccess)
        {
            throw new Exception("Can't be called from any thread than the dispatcher one");
        }

        NotifyCollectionChangedEventArgs args;
        while (this._uiItemQueue.TryDequeue(out args))
        {
            switch (args.Action)
            {
                case NotifyCollectionChangedAction.Add:
                    int offset = 0;
                    foreach (T item in args.NewItems)
                    {
                        ObsColl.Insert(args.NewStartingIndex + offset, item);
                        offset++;
                    }
                    break;
                case NotifyCollectionChangedAction.Remove:
                    if (args.NewStartingIndex >= 0)
                    {
                        ObsColl.RemoveAt(args.NewStartingIndex);
                    }
                    else
                    {
                        foreach (T item in args.OldItems)
                        {
                            ObsColl.Remove(item);
                        }
                    }
                    break;
                case NotifyCollectionChangedAction.Replace:
                    // Replace is used for the [] operator. 'Insert' raise an 'Add' event.

                    if (args.NewStartingIndex >= 0 && args.OldStartingIndex < 0)
                    {
                        throw new ArgumentException(String.Format("Replace action expect NewStartingIndex and OldStartingIndex as: 0 <= {0} <= {1}, {2} <= 0.", args.NewStartingIndex, ObsColl.Count, args.OldStartingIndex));
                    }

                    IList listOld = args.OldItems as IList;
                    IList listNew = args.NewItems as IList;

                    if (listOld == null || listNew == null)
                    {
                        throw new ArgumentException("Both argument Old and New item should be IList in a replace action.");
                    }

                    ObsColl[args.NewStartingIndex] = (T)listNew[0];
                    break;
                case NotifyCollectionChangedAction.Reset:
                    ObsColl.Clear();
                    break;
                case NotifyCollectionChangedAction.Move:
                    ObsColl.Move(args.OldStartingIndex, args.NewStartingIndex);
                    break;
                default:
                    throw new Exception("Unsupported NotifyCollectionChangedEventArgs.Action");
            }
        }
    }

    // ******************************************************************
    public List<T> GetSnapshot()
    {
        List<T> listCopy = null;

        lock (_syncRoot)
        {
            listCopy = new List<T>(List);
        }

        return listCopy;
    }

    // ******************************************************************
    public void GetSnapshot(IList list)
    {
        lock (_syncRoot)
        {
            List.ApplyForEachItem((path) => list.Add(path));
        }
    }

    // ******************************************************************
    public virtual IEnumerator<T> GetEnumerator()
    {
        return GetSnapshot().GetEnumerator();
    }

    // ******************************************************************
    public virtual IEnumerator<T> GetBlockingEnumerator()
    {
        return new BlockingIterator<T>(List.GetEnumerator(), _syncRoot);
    }

    // ******************************************************************
    System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
    {
        return GetSnapshot().GetEnumerator();
    }



    // ******************************************************************
    public void InsertAsFirst(T item)
    {
        NotifyCollectionChangedEventArgs args;
        lock (_syncRoot)
        {
            List.Insert(0, item);
            args = new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, item, 0);
            AddTask(args);
        }

        RaiseEventCollectionChanged(args);
    }

    // ******************************************************************
    public void Add(T item)
    {
        NotifyCollectionChangedEventArgs args;
        lock (_syncRoot)
        {
            List.Add(item);

            if (_isRecording)
            {
                _recordedNew.Add(item);
            }

            args = new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, item, List.Count - 1);
            AddTask(args);
        }

        RaiseEventCollectionChanged(args);
    }

    public void Add(IList<T> items)
    {
        NotifyCollectionChangedEventArgs args;
        lock (_syncRoot)
        {
            int insertIndex = List.Count;
            List.AddRange(items);

            if (_isRecording)
            {
                _recordedNew.AddRange(items);
            }

            args = new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, items as IList, insertIndex);
            AddTask(args);
        }

        RaiseEventCollectionChanged(args);
    }

    // ******************************************************************
    public bool Remove(T item)
    {
        bool isRemoved = false;

        NotifyCollectionChangedEventArgs args;
        lock (_syncRoot)
        {
            isRemoved = List.Remove(item);

            if (_isRecording)
            {
                _recordedNew.Add(item);
            }

            args = new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, item);
            AddTask(args);
        }

        RaiseEventCollectionChanged(args);

        return isRemoved;
    }

    // ******************************************************************
    public void Replace(T itemOld, T itemNew)
    {
        NotifyCollectionChangedEventArgs args = null;
        lock (_syncRoot)
        {
            int index = List.IndexOf(itemOld);
            if (index < 0 || index >= List.Count)
            {
                throw new ArgumentException("Invalid old value");
            }

            if (_isRecording)
            {
                _recordedNew.Add(itemNew);
                _recordedRemoved.Add(itemOld);
            }

            List[index] = itemNew;

            args = new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Replace, itemNew, itemOld, index);
            AddTask(args);
        }

        RaiseEventCollectionChanged(args);
    }

    // ******************************************************************
    private void RaiseEventCollectionChanged(NotifyCollectionChangedEventArgs args)
    {
        if (OnMtCollectionChanged != null && args != null)
        {
            OnMtCollectionChanged(this, args);
        }
    }

    // ******************************************************************
    /// <summary>
    /// To use this function and all 'Unsafe' ones in a MT context, 
    /// you should have a lock on the collection prior to call it.
    /// </summary>
    /// <param name="index"></param>
    /// <returns></returns>
    public T UnsafeGetAt(int index)
    {
        return List[index];
    }

    // ******************************************************************
    /// <summary>
    /// To use this function and all 'Unsafe' ones in a MT context, 
    /// you should have a lock on the collection prior to call it.
    /// </summary>
    /// <param name="index"></param>
    /// <param name="item"></param>
    /// <returns></returns>
    public T UnsafeSetAt(int index, T itemNew)
    {
        T itemOld = List[index];

        if (_isRecording)
        {
            _recordedNew.Add(itemNew);
            _recordedRemoved.Add(itemOld);
        }

        List[index] = itemNew;

        NotifyCollectionChangedEventArgs args = new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Replace, itemNew, itemOld, index);
        AddTask(args);

        RaiseEventCollectionChanged(args);

        return itemOld;
    }

    // ******************************************************************
    public void UnsafeInsertAt(int index, T itemNew)
    {
        if (_isRecording)
        {
            _recordedNew.Add(itemNew);
        }

        List.Insert(index, itemNew);

        NotifyCollectionChangedEventArgs args = new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, itemNew, index);
        AddTask(args);

        RaiseEventCollectionChanged(args);
    }

    // ******************************************************************
    /// <summary>
    /// To use this function and all 'Unsafe' ones in a MT context, 
    /// you should have a lock on the collection prior to call it.
    /// </summary>
    /// <param name="index"></param>
    /// <returns></returns>
    public T UnsafeRemoveAt(int index)
    {
        T itemOld = List[index];

        if (_isRecording)
        {
            _recordedRemoved.Add(itemOld);
        }

        List.RemoveAt(index);

        NotifyCollectionChangedEventArgs args = new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, itemOld, index);
        AddTask(args);

        RaiseEventCollectionChanged(args);

        return itemOld;
    }



    // ******************************************************************
    public virtual void Clear()
    {
        NotifyCollectionChangedEventArgs args = null;
        lock (_syncRoot)
        {
            if (_isRecording)
            {
                _recordedRemoved.AddRange(List);
            }

            List.Clear();
            args = new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset);
            AddTask(args);

        }

        RaiseEventCollectionChanged(args);
    }

    // ******************************************************************
    public bool Contains(T item)
    {
        bool result;
        lock (_syncRoot)
        {
            result = List.Contains(item);
        }

        return result;
    }

    // ******************************************************************
    public void CopyTo(T[] array, int arrayIndex)
    {
        lock (_syncRoot)
        {
            List.CopyTo(array, arrayIndex);
        }
    }

    // ******************************************************************
    public int Count
    {
        get
        {
            lock (_syncRoot)
            {
                return List.Count;
            }
        }
    }

    // ******************************************************************
    public void Remove(object item)
    {
        Remove((T)item);
    }

    // ******************************************************************
    public int IndexOf(object value)
    {
        return IndexOf((T)value);
    }



    // ******************************************************************
    public object SyncRoot
    {
        get { return _syncRoot; }
    }

    // ******************************************************************
    public bool IsEqual(IEnumerable<T> iEnumerable)
    {
        if (this.Count != iEnumerable.Count())
        {
            return false;
        }

        lock (_syncRoot)
        {
            var thisEnumerator = this.GetEnumerator();
            thisEnumerator.Reset();
            foreach (var t in iEnumerable)
            {
                thisEnumerator.MoveNext();
                if (thisEnumerator.Current.Equals(t))
                {
                    return false;
                }
            }

            Disposal.Dispose(thisEnumerator);
        }

        return true;
    }

    // ******************************************************************
    private void IsEqualToObsColl()
    {
        if (!IsEqual(this.ObsColl))
        {
            Dump();
        }
    }

    // ******************************************************************
    /// <summary>
    /// This function dumps to the ouput window formated lines of the content of both collections...
    /// The list which is thread safe and the obs coll that is used as a readonly list. 
    /// Its main purpose is to debug to validate that both list contains the same values in the same order.
    /// </summary>
    private void Dump()
    {
        Debug.WriteLine("=============== Start");

        lock (_syncRoot)
        {
            IEnumerator enum1 = List.GetEnumerator();
            IEnumerator enum2 = ObsColl.GetEnumerator();

            enum1.Reset();
            enum2.Reset();

            bool ok1 = enum1.MoveNext();
            bool ok2 = enum2.MoveNext();

            while (ok1 || ok2)
            {
                Debug.WriteLine(String.Format("{0,20} - {0,-20}", ok1 == true ? enum1.Current : "-", ok2 == true ? enum2.Current : "-"));

                if (ok1)
                    ok1 = enum1.MoveNext();

                if (ok2)
                    ok2 = enum2.MoveNext();
            }

            Disposal.Dispose(enum1);
            Disposal.Dispose(enum2);

        }

        Debug.WriteLine("=============== End");
    }


    // ******************************************************************
    [OnSerializing]
    void OnSerializing(StreamingContext ctx)
    {
        Monitor.Enter(this._syncRoot);
    }

    // ******************************************************************
    [OnSerialized]
    void OnSerialized(StreamingContext ctx)
    {
        Monitor.Exit(this._syncRoot);
    }

    // ******************************************************************
    [OnDeserializing]
    void OnDeserializing(StreamingContext ctx)
    {

    }

    // ******************************************************************
    [OnDeserialized]
    void OnDeserialized(StreamingContext ctx)
    {

    }

    // ******************************************************************
    /// <summary>
    /// ATTENTION : This method is not MT safe
    /// </summary>
    /// <param name="index"></param>
    /// <returns></returns>
    public T this[int index]
    {
        get { return this.List[index]; }
    }

    // ******************************************************************
    /// <summary>
    /// Add stack functionnality to use the list as a queue
    /// </summary>
    /// <param name="item"></param>
    public void Push(T item)
    {
        Add(item);
    }

    // ******************************************************************
    /// <summary>
    /// Add stack functionnality to use the list as a queue
    /// </summary>
    /// <returns></returns>
    public bool TryPop(out T item)
    {
        lock (_syncRoot)
        {
            int count = List.Count;
            if (count > 0)
            {
                item = UnsafeRemoveAt(count - 1);
                return true;
            }
        }

        item = default(T);
        return false;
    }

    // ******************************************************************
    /// <summary>
    /// Add queue functionnality to use the list as a queue. Item are added at the end of the list
    /// </summary>
    /// <param name="item"></param>
    public void Enqueue(T item)
    {
        Add(item);
    }

    // ******************************************************************
    /// <summary>
    ///  Add queue functionnality to use the list as a queue. Item are removed at position 0 (cost a lot due to move all array item left from one position)
    /// </summary>
    /// <returns></returns>
    public bool TryDequeue(out T item)
    {
        lock (_syncRoot)
        {
            int count = List.Count;
            if (count > 0)
            {
                item = UnsafeRemoveAt(0);
                return true;
            }
        }

        item = default(T);
        return false;
    }

    // ******************************************************************
    public bool IsReadOnly
    {
        get { return false; }
    }

    // ******************************************************************
    bool ICollection<T>.Remove(T item)
    {
        return Remove(item);
    }

    // ******************************************************************
    public void CopyTo(Array array, int index)
    {
        lock (_syncRoot)
        {
            foreach (var t in List)
            {
                array.SetValue(t, index++);
            }
        }
    }

    // ******************************************************************
    public bool IsSynchronized
    {
        get { return Dispatcher.HasThreadAccess; }
    }

    // ******************************************************************

}
在tcollectionChangedHandler(对象发送方,NotifyCollectionChangedEventArgs args)上的公共委托无效;
[数据合同]
公共类AsyncObservableCollection:ICollection,DirectAdonlyList
{
// ******************************************************************
私有列表_recordedNew=新列表();
私有列表_recordedRemoved=新列表();
私有bool _isRecording=false;
私有只读对象_syncRoot=新对象();
受保护列表=新列表();
私有只读ObservableCollection _obsColl=新ObservableCollection();
私有只读ConcurrentQueue _uiItemQueue=新ConcurrentQueue();
OnMtCollectionChangedHandler OnMtCollectionChanged的公共事件;
公共CoreDispatcher调度程序{get;set;}
// ******************************************************************
/// 
///不应直接在集合中添加任何项目。
///它应该只作为UI的只读集合。
///如果您决定这样做,最好直接使用OBS集合
///从未使用过此类(类似于分离)
/// 
公共可观测收集ObsColl
{
获取{return\u obsColl;}
}
// ******************************************************************
公共AsyncObservableCollection()
{
//Dispatcher=Application.Current;
Dispatcher=Window.Current.Dispatcher;
}
公共AsyncObservableCollection(集合集合)
{
//Dispatcher=Application.Current;
Dispatcher=Window.Current.Dispatcher;
this.Add(collection.ToList());
}
// ******************************************************************
公共图书馆记录
{
获取{return\u isRecording;}
设置{u isRecording=value;}
}
// ******************************************************************
/// 
///返回新项和已删除项的元组
/// 
/// 
公共元组ResetRecordedItems()
{
元组变化;
锁定(\u syncRoot)
{
更改=新元组(_recordedNew,_recordedRemoved);
_recordedNew=新列表();
_recordedRemoved=新列表();
}
回报变化;
}
// ******************************************************************
公共T[]GetCopyOfRecordeditNew()
{
T[]变化;
锁定(\u syncRoot)
{
更改=_recordedNew.ToArray();
}
回报变化;
}
// ******************************************************************
公共T[]GetCopyOfRecordedItemsRemoved()
{
T[]变化;
锁定(\u syncRoot)
{
更改=_recordedRemoved.ToArray();
}
回报变化;
}
// ******************************************************************
专用异步void AddTask(NotifyCollectionChangedEventArgs args)
{
_uiItemQueue.Enqueue(args);
//Dispatcher.BeginInvoke(新操作(this.ProcessQueue));
wait Dispatcher.RunAsync(CoreDispatcherPriority.Normal,()=>
{
this.ProcessQueue();
});
}
// ******************************************************************
私有void ProcessQueue()
{
//此方法应始终仅由UI线程调用。
如果(!this.Dispatcher.HasThreadAccess)
{
抛出新异常(“不能从调度程序线程以外的任何线程调用”);
}
NotifyCollectionChangedEventArgs参数;
while(this.\u uiItemQueue.TryDequeue(out args))
{
开关(参数操作)
{
案例NotifyCollectionChangedAction。添加:
整数偏移=0;
foreach(args.NewItems中的T项)
{
ObsColl.Insert(args.NewStartingIndex+偏移量,项目);
offset++;
}
打破
案例NotifyCollectionChangedAction。删除:
如果(args.NewStartingIndex>=0)
{
ObsColl.RemoveAt(参数NewStartingIndex);
}
其他的
{
foreach(参数OldItems中的T项)
{
移除障碍物(项目);
}
}
打破
案例通知收集更改操作。替换:
//替换用于[]运算符。“插入”引发“添加”事件。
如果(args.NewStartingIndex>=0&&args.OldStartingIndex<0)
{

抛出新ArgumentException(String.Format(“替换操作,期望NewsStartingIndex和OldStartingIndex为:0好吧,代码示例中缺少一些内容,因此我无法编译它(
Disposition
ApplyForEachItem
),但我可以看到您有一个
公共无效添加(t项)
公共无效添加(IList项)
方法。接口实现在