//--------------------------------------------------------------------- // <copyright file="ObjectViewEntityCollectionData.cs" company="Microsoft"> // Copyright (c) Microsoft Corporation. All rights reserved. // </copyright> // // @owner Microsoft // @backupOwner Microsoft //--------------------------------------------------------------------- using System; using System.Collections.Generic; using System.ComponentModel; using System.Data.Objects.DataClasses; using System.Data.Objects.Internal; using System.Diagnostics; using System.Data.Common; namespace System.Data.Objects { /// <summary> /// Manages a binding list constructed from an EntityCollection. /// </summary> /// <typeparam name="TViewElement"> /// Type of the elements in the binding list. /// </typeparam> /// <typeparam name="TItemElement"> /// Type of element in the underlying EntityCollection. /// </typeparam> /// <remarks> /// The binding list is initialized from the EntityCollection, /// and is synchronized with changes made to the EntityCollection membership. /// This class always allows additions and removals from the binding list. /// </remarks> internal sealed class ObjectViewEntityCollectionData<TViewElement, TItemElement> : IObjectViewData<TViewElement> where TItemElement : class where TViewElement : TItemElement { private List<TViewElement> _bindingList; private EntityCollection<TItemElement> _entityCollection; private readonly bool _canEditItems; /// <summary> /// <b>True</b> if item that was added to binding list but not underlying entity collection /// is now being committed to the collection. /// Otherwise <b>false</b>. /// Used by CommitItemAt and OnCollectionChanged methods to coordinate addition /// of new item to underlying entity collection. /// </summary> private bool _itemCommitPending; /// <summary> /// Construct a new instance of the ObjectViewEntityCollectionData class using the supplied entityCollection. /// </summary> /// <param name="entityCollection"> /// EntityCollection used to populate the binding list. /// </param> internal ObjectViewEntityCollectionData(EntityCollection<TItemElement> entityCollection) { _entityCollection = entityCollection; _canEditItems = true; // Allow deferred loading to occur when initially populating the collection _bindingList = new List<TViewElement>(entityCollection.Count); foreach (TViewElement entity in entityCollection) { _bindingList.Add(entity); } } #region IObjectViewData<TViewElement> Members public IList<TViewElement> List { get { return _bindingList; } } public bool AllowNew { get { return !_entityCollection.IsReadOnly; } } public bool AllowEdit { get { return _canEditItems; } } public bool AllowRemove { get { return !_entityCollection.IsReadOnly; } } public bool FiresEventOnAdd { get { return true; } } public bool FiresEventOnRemove { get { return true; } } public bool FiresEventOnClear { get { return true; } } public void EnsureCanAddNew() { // nop } public int Add(TViewElement item, bool isAddNew) { if (isAddNew) { // Item is added to bindingList, but pending addition to entity collection. _bindingList.Add(item); } else { _entityCollection.Add(item); // OnCollectionChanged will be fired, where the binding list will be updated. } return _bindingList.Count - 1; } public void CommitItemAt(int index) { TViewElement item = _bindingList[index]; try { _itemCommitPending = true; _entityCollection.Add(item); // OnCollectionChanged will be fired, where the binding list will be updated. } finally { _itemCommitPending = false; } } public void Clear() { if (0 < _bindingList.Count) { List<object> _deletionList = new List<object>(); foreach (object item in _bindingList) { _deletionList.Add(item); } _entityCollection.BulkDeleteAll(_deletionList); // EntityCollection will fire change event which this instance will use to clean up the binding list. } } public bool Remove(TViewElement item, bool isCancelNew) { bool removed; if (isCancelNew) { // Item was previously added to binding list, but not entity collection. removed = _bindingList.Remove(item); } else { removed = _entityCollection.RemoveInternal(item); // OnCollectionChanged will be fired, where the binding list will be updated. } return removed; } public ListChangedEventArgs OnCollectionChanged(object sender, CollectionChangeEventArgs e, ObjectViewListener listener) { ListChangedEventArgs changeArgs = null; switch (e.Action) { case CollectionChangeAction.Remove: // An Entity is being removed from entity collection, remove it from list. if (e.Element is TViewElement) { TViewElement removedItem = (TViewElement)e.Element; int oldIndex = _bindingList.IndexOf(removedItem); if (oldIndex != -1) { _bindingList.Remove(removedItem); // Unhook from events of removed entity. listener.UnregisterEntityEvents(removedItem); changeArgs = new ListChangedEventArgs(ListChangedType.ItemDeleted, oldIndex /* newIndex*/, -1 /* oldIndex*/); } } break; case CollectionChangeAction.Add: // Add the entity to our list. if (e.Element is TViewElement) { // Do not process Add events that fire as a result of committing an item to the entity collection. if (!_itemCommitPending) { TViewElement addedItem = (TViewElement)e.Element; _bindingList.Add(addedItem); // Register to its events. listener.RegisterEntityEvents(addedItem); changeArgs = new ListChangedEventArgs(ListChangedType.ItemAdded, _bindingList.Count - 1 /* newIndex*/, -1 /* oldIndex*/); } } break; case CollectionChangeAction.Refresh: foreach (TViewElement entity in _bindingList) { listener.UnregisterEntityEvents(entity); } _bindingList.Clear(); foreach(TViewElement entity in _entityCollection.GetInternalEnumerable()) { _bindingList.Add(entity); listener.RegisterEntityEvents(entity); } changeArgs = new ListChangedEventArgs(ListChangedType.Reset, -1 /*newIndex*/, -1/*oldIndex*/); break; } return changeArgs; } #endregion } }