2016-04-07 4 views
1

Ich habe versucht, die asynchrone Auflistung von Link to original für UWP anzupassen. Aber wenn ich versuche, die Datei zu erstellen, erhalte ich folgende Fehlermeldung:Seltsame Build-Ausnahme nach Anpassung von AsyncObservableCollection für UWP

Severity Code Description Project File Line Suppression State Error Cannot determine the item type of collection type 'Logic.Model.AsyncObservableCollection`1[DataAccess.Core.ch.Phex.API.Customer]' because it has more than one Add method or ICollection implementation. To make this collection type usable in XAML, add a public Add(object) method, implement System.Collections.IList or a single System.Collections.Generic.ICollection. Ui.Windows

Kann mir jemand einen Tipp geben?

Mit freundlichen Grüßen Kaffi

Source Code

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; } 
    } 

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

} 

Antwort

0

Nun du verpasst ein paar Dinge aus dem Codebeispiel, so konnte ich es nicht kompilieren (Disposal und ApplyForEachItem), aber ich kann sehen, dass Sie eine public void Add(T item) und eine public void Add(IList<T> items) Methode auch haben. Die Implementierung der Schnittstelle erfordert nur die erste - für die zweite ist die übliche Namenskonvention AddRange.

+0

Danke für die Antwort Die anderen Klassen wie Entsorgung oder die Funktion ApplyForEachItem sind in anderen Klassen-Dateien definiert und ich denke, sie funktionieren ohne Probleme. Ich werde versuchen, wenn es ausreicht, eine der Funktionen in AddRange umzubenennen. Ich werde mich melden, sobald ich Zeit habe zu überprüfen. – Kaffi

+0

Es war die AddRange Benennung der Funktion. Danke! – Kaffi

+0

Ehrfürchtig, glücklich zu helfen. –