using System; using System.Collections.Generic; using System.Text; using System.Runtime.Serialization; using System.ComponentModel; namespace Csla { /// /// This is the base class from which collections /// of editable root business objects should be /// derived. /// /// /// Type of editable root object to contain within /// the collection. /// /// /// /// Your subclass should implement a factory method /// and should override or overload /// DataPortal_Fetch() to implement data retrieval. /// /// Saving (inserts or updates) of items in the collection /// should be handled through the SaveItem() method on /// the collection. /// /// Removing an item from the collection /// through Remove() or RemoveAt() causes immediate deletion /// of the object, by calling the object's Delete() and /// Save() methods. /// /// [Serializable()] public abstract class EditableRootListBase : Core.ExtendedBindingList, Core.IParent where T : Core.IEditableBusinessObject, Core.ISavable { #region SaveItem Methods private bool _activelySaving; /// /// Saves the specified item in the list. /// /// /// Reference to the item to be saved. /// /// /// This method properly saves the child item, /// by making sure the item in the collection /// is properly replaced by the result of the /// Save() method call. /// public void SaveItem(T item) { SaveItem(IndexOf(item)); } /// /// Saves the specified item in the list. /// /// /// Index of the item to be saved. /// /// /// This method properly saves the child item, /// by making sure the item in the collection /// is properly replaced by the result of the /// Save() method call. /// public virtual void SaveItem(int index) { bool raisingEvents = this.RaiseListChangedEvents; this.RaiseListChangedEvents = false; _activelySaving = true; T item = this[index]; int editLevel = item.EditLevel; // commit all changes for (int tmp = 1; tmp <= editLevel; tmp++) item.AcceptChanges(); try { // do the save this[index] = (T)item.Save(); } finally { // restore edit level to previous level for (int tmp = 1; tmp <= editLevel; tmp++) item.CopyState(); _activelySaving = false; this.RaiseListChangedEvents = raisingEvents; } this.OnListChanged(new ListChangedEventArgs(ListChangedType.ItemChanged, index)); } #endregion #region Insert, Remove, Clear /// /// Gives the new object a parent reference to this /// list. /// /// Index at which to insert the item. /// Item to insert. protected override void InsertItem(int index, T item) { item.SetParent(this); base.InsertItem(index, item); } /// /// Removes an item from the list. /// /// Index of the item /// to be removed. protected override void RemoveItem(int index) { // delete item from database T item = this[index]; // only delete/save the item if it is not new if (!item.IsNew) { item.Delete(); SaveItem(index); } // disconnect event handler if necessary System.ComponentModel.INotifyPropertyChanged c = item as System.ComponentModel.INotifyPropertyChanged; if (c != null) { c.PropertyChanged -= new System.ComponentModel.PropertyChangedEventHandler(Child_PropertyChanged); } base.RemoveItem(index); } #endregion #region IParent Members void Csla.Core.IParent.ApplyEditChild(Core.IEditableBusinessObject child) { if (!_activelySaving && child.EditLevel == 0) SaveItem((T)child); } void Csla.Core.IParent.RemoveChild(Core.IEditableBusinessObject child) { // do nothing, removal of a child is handled by // the RemoveItem override } #endregion #region Cascade Child events private void Child_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e) { for (int index = 0; index < this.Count; index++) { if (ReferenceEquals(this[index], sender)) { OnListChanged(new System.ComponentModel.ListChangedEventArgs(System.ComponentModel.ListChangedType.ItemChanged, index)); break; } } } #endregion #region Serialization Notification [OnDeserialized()] private void OnDeserializedHandler(StreamingContext context) { OnDeserialized(context); foreach (Core.IEditableBusinessObject child in this) { child.SetParent(this); System.ComponentModel.INotifyPropertyChanged c = child as System.ComponentModel.INotifyPropertyChanged; if (c != null) { c.PropertyChanged += new System.ComponentModel.PropertyChangedEventHandler(Child_PropertyChanged); } } } /// /// This method is called on a newly deserialized object /// after deserialization is complete. /// /// Serialization context object. [EditorBrowsable(EditorBrowsableState.Advanced)] protected virtual void OnDeserialized(StreamingContext context) { // do nothing - this is here so a subclass // could override if needed } #endregion #region Data Access [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId = "criteria")] private void DataPortal_Create(object criteria) { throw new NotSupportedException(Properties.Resources.CreateNotSupportedException); } /// /// Override this method to allow retrieval of an existing business /// object based on data in the database. /// /// An object containing criteria values to identify the object. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1707:IdentifiersShouldNotContainUnderscores", MessageId = "Member")] protected virtual void DataPortal_Fetch(object criteria) { throw new NotSupportedException(Properties.Resources.FetchNotSupportedException); } private void DataPortal_Update() { throw new NotSupportedException(Properties.Resources.UpdateNotSupportedException); } [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId = "criteria")] private void DataPortal_Delete(object criteria) { throw new NotSupportedException(Properties.Resources.DeleteNotSupportedException); } /// /// Called by the server-side DataPortal prior to calling the /// requested DataPortal_xyz method. /// /// The DataPortalContext object passed to the DataPortal. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1707:IdentifiersShouldNotContainUnderscores", MessageId = "Member"), EditorBrowsable(EditorBrowsableState.Advanced)] protected virtual void DataPortal_OnDataPortalInvoke(DataPortalEventArgs e) { } /// /// Called by the server-side DataPortal after calling the /// requested DataPortal_xyz method. /// /// The DataPortalContext object passed to the DataPortal. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1707:IdentifiersShouldNotContainUnderscores", MessageId = "Member"), EditorBrowsable(EditorBrowsableState.Advanced)] protected virtual void DataPortal_OnDataPortalInvokeComplete(DataPortalEventArgs e) { } /// /// Called by the server-side DataPortal if an exception /// occurs during data access. /// /// The DataPortalContext object passed to the DataPortal. /// The Exception thrown during data access. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1707:IdentifiersShouldNotContainUnderscores", MessageId = "Member"), EditorBrowsable(EditorBrowsableState.Advanced)] protected virtual void DataPortal_OnDataPortalException(DataPortalEventArgs e, Exception ex) { } #endregion } }