void OnOuterMove(object sender, int oldStartingIndex, IEnumerable <TOuter> oldItems, int newStartingIndex, IEnumerable <TOuter> newItems)
        {
            List <TResult> movedResults = new List <TResult>(1);

            foreach (var item in newItems)
            {
                OuterEntry entryForItem = _outerEntries[item];
                movedResults.Add(entryForItem.Result);
            }

            FireMove(movedResults, newStartingIndex, oldStartingIndex);
        }
        private void OnOuterRemove(object sender, int index, IEnumerable <TOuter> oldItems)
        {
            List <TResult> oldResults = new List <TResult>(1);

            foreach (var item in oldItems)
            {
                OuterEntry entry = RemoveOuter(item);
                oldResults.Add(entry.Result);
            }

            FireRemove(oldResults, index);
        }
        private void OnOuterAdd(object sender, int index, IEnumerable <TOuter> newItems)
        {
            List <TResult> newResults = new List <TResult>(1);

            foreach (var item in newItems)
            {
                OuterEntry entry = RecordOuter(item);
                newResults.Add(entry.Result);
            }

            FireAdd(newResults, index);
        }
        private void AddAllInnersMatchingKey(OuterEntry outerEntry)
        {
            List <TInner> innersMatchingKey;

            if (_keyToInnerLookup.TryGetValue(outerEntry.Key, out innersMatchingKey))
            {
                for (int i = 0; i < innersMatchingKey.Count; i++)
                {
                    var innerItem = innersMatchingKey[i];
                    outerEntry.MatchingInners.Add(innerItem);
                }
            }
        }
        void OnOuterItemReplace(object sender, IEnumerable <TOuter> oldItems, int newStartingIndex, IEnumerable <TOuter> newItems)
        {
            List <TResult> oldResults = new List <TResult>(1);

            foreach (var item in oldItems)
            {
                OuterEntry entry = RemoveOuter(item);
                oldResults.Add(entry.Result);
            }

            List <TResult> newResults = new List <TResult>(1);

            foreach (var item in newItems)
            {
                OuterEntry entry = RecordOuter(item);
                newResults.Add(entry.Result);
            }

            FireReplace(newResults, oldResults, newStartingIndex);
        }
        private OuterEntry RemoveOuter(TOuter outerItem)
        {
            OuterEntry outerEntry = _outerEntries[outerItem];

            if (_outerReferenceTracker.Remove(outerItem))
            {
                _outerEntries.Remove(outerItem);

                List <OuterEntry> outersMatchingKey = _keyToOuterLookup[outerEntry.Key];
                if (outersMatchingKey.Count == 1)
                {
                    _keyToOuterLookup.Remove(outerEntry.Key);
                }
                else
                {
                    outersMatchingKey.Remove(outerEntry);
                }
            }

            return(outerEntry);
        }
        private OuterEntry RecordOuter(TOuter outerItem)
        {
            _outerReferenceTracker.Add(outerItem);

            OuterEntry outerEntry;

            if (!_outerEntries.TryGetValue(outerItem, out outerEntry))
            {
                TKey outerKey = _outerKeySelector(outerItem);

                outerEntry = new OuterEntry(outerItem, outerKey);

                outerEntry.Result = _resultSelector(outerItem, outerEntry.MatchingInnersReadOnly);

                _outerEntries[outerItem] = outerEntry;

                var outersMatchingKey = _keyToOuterLookup.GetOrCreate(outerKey, () => new List <OuterEntry>(1));
                outersMatchingKey.Add(outerEntry);

                AddAllInnersMatchingKey(outerEntry);
            }

            return(outerEntry);
        }