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