private void AdapterCreationCallback(TSourceEnumerationItem sourceValue)
            {
                try
                {
                    //Replace item with a newly created adapter
                    var OldItem = this.items.First(_ => object.Equals(_.SourceValue, sourceValue));

                    ObservableExpressionFactory.EventSink EventSink = new ObservableExpressionFactory.EventSink((sender, e) => this.AdapterCreationCallback(sourceValue));
                    CachedValueCollectionItem             NewItem   = new CachedValueCollectionItem(sourceValue, this.adapter.adapterCreation(this.source, sourceValue, EventSink), EventSink);

                    this.Replace(OldItem, NewItem);
                }
                catch (Exception)
                {
                    // Something happend while converting and/or adding the item. Reset the colleciton and retry 'from scratch'
                    this.adapter.NotifyItemUpdateFailed(this.source);
                }
            }
 public CachedValueCollectionItem(TSourceEnumerationItem sourceValue, TTargetEnumerationItem targetValue, ObservableExpressionFactory.EventSink eventSink)
 {
     this.eventSink   = eventSink;
     this.SourceValue = sourceValue;
     this.TargetValue = targetValue;
 }
            public void Update(IEnumerable <TSourceEnumerationItem> values)
            {
                TSourceEnumerationItem[] Values = values != null?values.ToArray() : new TSourceEnumerationItem[0];

                if (Values.Length > 0)
                {
                    //First delete items to avoid unneeded move operations. save in arraqy to be able to modify the source collection
                    foreach (CachedValueCollectionItem ItemToDelete in this.items.Where(item => Values.Any(value => object.Equals(value, item.SourceValue)) == false).ToArray())
                    {
                        this.Remove(ItemToDelete);
                    }

                    ObservableCollection <CachedValueCollectionItem> OldValues = new ObservableCollection <CachedValueCollectionItem>(this.items.ToArray());

                    //Move existing entries to new locations and eventually add new entries
                    for (int Index = 0; Index < Values.Length; Index++)
                    {
                        if (OldValues.Count > Index && object.Equals(OldValues[Index], Values[Index]))
                        {
                            //Item is still the same -> nothing to do
                            DebugLogger.WriteLine(this, LoggingLevel.Verbose, () => $"Collection Update: index {Index} stays unchanged");
                        }
                        else
                        {
                            //Search for the item. first we have to find the item in the cache to get the index. Skip already sorted entries to allow handling of equal objects in the same list
                            int SearchIndex = OldValues.IndexOf(OldValues.Skip(Index).FirstOrDefault(_ => object.Equals(_.SourceValue, Values[Index])));
                            if (SearchIndex != -1)
                            {
                                //Found in the list
                                if (Index != SearchIndex)
                                {
                                    //-> move to front
                                    DebugLogger.WriteLine(this, LoggingLevel.Verbose, () => $"Collection Update: Move  index {SearchIndex} to index {Index}");

                                    this.Move(SearchIndex, Index);
                                    OldValues.Move(SearchIndex, Index);
                                }
                                else
                                {
                                    //Position already matches -> do nothing
                                }
                            }
                            else
                            {
                                //Not found -> must be new
                                DebugLogger.WriteLine(this, LoggingLevel.Verbose, () => $"Collection Update: Add new item at index {Index}");

                                TSourceEnumerationItem SourceValue = Values[Index];
                                ObservableExpressionFactory.EventSink EventSink = new ObservableExpressionFactory.EventSink((sender, e) => this.AdapterCreationCallback(SourceValue));
                                CachedValueCollectionItem             NewItem   = new CachedValueCollectionItem(SourceValue,
                                                                                                                this.adapter.adapterCreation(this.source, SourceValue, EventSink), EventSink);
                                this.Insert(Index, NewItem);
                                OldValues.Insert(Index, NewItem);
                            }
                        }
                    }
                }
                else
                {
                    this.ClearItems();
                }
            }