Commit for development environment setup

This commit is contained in:
2023-06-19 16:12:33 -04:00
parent be72063a3c
commit bbce2ad0a6
2209 changed files with 1171775 additions and 625 deletions

View File

@@ -0,0 +1,107 @@
using System;
using System.ComponentModel;
using System.Reflection;
namespace Csla.Core
{
/// <summary>
/// This class implements INotifyPropertyChanged
/// in a serialization-safe manner.
/// </summary>
[Serializable()]
public abstract class BindableBase : System.ComponentModel.INotifyPropertyChanged
{
[NonSerialized()]
private PropertyChangedEventHandler _nonSerializableHandlers;
private PropertyChangedEventHandler _serializableHandlers;
/// <summary>
/// Creates an instance of the object.
/// </summary>
protected BindableBase()
{
}
/// <summary>
/// Implements a serialization-safe PropertyChanged event.
/// </summary>
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design",
"CA1062:ValidateArgumentsOfPublicMethods")]
public event PropertyChangedEventHandler PropertyChanged
{
add
{
if (value.Method.IsPublic &&
(value.Method.DeclaringType.IsSerializable ||
value.Method.IsStatic))
_serializableHandlers = (PropertyChangedEventHandler)
System.Delegate.Combine(_serializableHandlers, value);
else
_nonSerializableHandlers = (PropertyChangedEventHandler)
System.Delegate.Combine(_nonSerializableHandlers, value);
}
remove
{
if (value.Method.IsPublic &&
(value.Method.DeclaringType.IsSerializable ||
value.Method.IsStatic))
_serializableHandlers = (PropertyChangedEventHandler)
System.Delegate.Remove(_serializableHandlers, value);
else
_nonSerializableHandlers = (PropertyChangedEventHandler)
System.Delegate.Remove(_nonSerializableHandlers, value);
}
}
/// <summary>
/// Call this method to raise the PropertyChanged event
/// for all object properties.
/// </summary>
/// <remarks>
/// This method is for backward compatibility with
/// CSLA .NET 1.x.
/// </remarks>
[EditorBrowsable(EditorBrowsableState.Advanced)]
protected virtual void OnIsDirtyChanged()
{
OnUnknownPropertyChanged();
}
/// <summary>
/// Call this method to raise the PropertyChanged event
/// for all object properties.
/// </summary>
/// <remarks>
/// This method is automatically called by MarkDirty. It
/// actually raises PropertyChanged for an empty string,
/// which tells data binding to refresh all properties.
/// </remarks>
[EditorBrowsable(EditorBrowsableState.Advanced)]
protected virtual void OnUnknownPropertyChanged()
{
OnPropertyChanged(string.Empty);
}
/// <summary>
/// Call this method to raise the PropertyChanged event
/// for a specific property.
/// </summary>
/// <param name="propertyName">Name of the property that
/// has changed.</param>
/// <remarks>
/// This method may be called by properties in the business
/// class to indicate the change in a specific property.
/// </remarks>
[EditorBrowsable(EditorBrowsableState.Advanced)]
protected virtual void OnPropertyChanged(string propertyName)
{
if (_nonSerializableHandlers != null)
_nonSerializableHandlers.Invoke(this,
new PropertyChangedEventArgs(propertyName));
if (_serializableHandlers != null)
_serializableHandlers.Invoke(this,
new PropertyChangedEventArgs(propertyName));
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,85 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.ComponentModel;
namespace Csla.Core
{
/// <summary>
/// Extends BindingList of T by adding extra
/// events.
/// </summary>
/// <typeparam name="T">Type of item contained in list.</typeparam>
[Serializable]
public class ExtendedBindingList<T> : BindingList<T>, IExtendedBindingList
{
#region RemovingItem event
[NonSerialized()]
private EventHandler<RemovingItemEventArgs> _nonSerializableHandlers;
private EventHandler<RemovingItemEventArgs> _serializableHandlers;
/// <summary>
/// Implements a serialization-safe RemovingItem event.
/// </summary>
public event EventHandler<RemovingItemEventArgs> RemovingItem
{
add
{
if (value.Method.IsPublic &&
(value.Method.DeclaringType.IsSerializable ||
value.Method.IsStatic))
_serializableHandlers = (EventHandler<RemovingItemEventArgs>)
System.Delegate.Combine(_serializableHandlers, value);
else
_nonSerializableHandlers = (EventHandler<RemovingItemEventArgs>)
System.Delegate.Combine(_nonSerializableHandlers, value);
}
remove
{
if (value.Method.IsPublic &&
(value.Method.DeclaringType.IsSerializable ||
value.Method.IsStatic))
_serializableHandlers = (EventHandler<RemovingItemEventArgs>)
System.Delegate.Remove(_serializableHandlers, value);
else
_nonSerializableHandlers = (EventHandler<RemovingItemEventArgs>)
System.Delegate.Remove(_nonSerializableHandlers, value);
}
}
/// <summary>
/// Raise the RemovingItem event.
/// </summary>
/// <param name="removedItem">
/// A reference to the item that
/// is being removed.
/// </param>
[EditorBrowsable(EditorBrowsableState.Advanced)]
protected void OnRemovingItem(T removedItem)
{
if (_nonSerializableHandlers != null)
_nonSerializableHandlers.Invoke(this,
new RemovingItemEventArgs(removedItem));
if (_serializableHandlers != null)
_serializableHandlers.Invoke(this,
new RemovingItemEventArgs(removedItem));
}
#endregion
/// <summary>
/// Remove the item at the
/// specified index.
/// </summary>
/// <param name="index">
/// The zero-based index of the item
/// to remove.
/// </param>
protected override void RemoveItem(int index)
{
OnRemovingItem(this[index]);
base.RemoveItem(index);
}
}
}

View File

@@ -0,0 +1,10 @@
namespace Csla.Core
{
/// <summary>
/// This is the core interface implemented
/// by all CSLA .NET base classes.
/// </summary>
public interface IBusinessObject
{
}
}

View File

@@ -0,0 +1,14 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Csla.Core
{
/// <summary>
/// This interface is implemented by all
/// Command objects.
/// </summary>
interface ICommandObject : IBusinessObject
{
}
}

View File

@@ -0,0 +1,126 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Csla.Core
{
/// <summary>
/// Defines the common methods required by all
/// editable CSLA single objects.
/// </summary>
/// <remarks>
/// It is strongly recommended that the implementations
/// of the methods in this interface be made Private
/// so as to not clutter up the native interface of
/// the collection objects.
/// </remarks>
public interface IEditableBusinessObject : IUndoableObject
{
/// <summary>
/// Returns <see langword="true" /> if this object's data has been changed.
/// </summary>
/// <remarks>
/// <para>
/// When an object's data is changed, CSLA .NET makes note of that change
/// and considers the object to be 'dirty' or changed. This value is used to
/// optimize data updates, since an unchanged object does not need to be
/// updated into the database. All new objects are considered dirty. All objects
/// marked for deletion are considered dirty.
/// </para><para>
/// Once an object's data has been saved to the database (inserted or updated)
/// the dirty flag is cleared and the object is considered unchanged. Objects
/// newly loaded from the database are also considered unchanged.
/// </para>
/// </remarks>
/// <returns>A value indicating if this object's data has been changed.</returns>
bool IsDirty { get;}
/// <summary>
/// Returns <see langword="true" /> if the object is currently valid, <see langword="false" /> if the
/// object has broken rules or is otherwise invalid.
/// </summary>
/// <remarks>
/// <para>
/// By default this property relies on the underling ValidationRules
/// object to track whether any business rules are currently broken for this object.
/// </para><para>
/// You can override this property to provide more sophisticated
/// implementations of the behavior. For instance, you should always override
/// this method if your object has child objects, since the validity of this object
/// is affected by the validity of all child objects.
/// </para>
/// </remarks>
/// <returns>A value indicating if the object is currently valid.</returns>
bool IsValid { get;}
/// <summary>
/// Returns <see langword="true" /> if this object is marked for deletion.
/// </summary>
/// <remarks>
/// CSLA .NET supports both immediate and deferred deletion of objects. This
/// property is part of the support for deferred deletion, where an object
/// can be marked for deletion, but isn't actually deleted until the object
/// is saved to the database. This property indicates whether or not the
/// current object has been marked for deletion. If it is <see langword="true" />
/// , the object will
/// be deleted when it is saved to the database, otherwise it will be inserted
/// or updated by the save operation.
/// </remarks>
/// <returns>A value indicating if this object is marked for deletion.</returns>
bool IsDeleted { get;}
/// <summary>
/// Returns <see langword="true" /> if this is a new object,
/// <see langword="false" /> if it is a pre-existing object.
/// </summary>
/// <remarks>
/// An object is considered to be new if its primary identifying (key) value
/// doesn't correspond to data in the database. In other words,
/// if the data values in this particular
/// object have not yet been saved to the database the object is considered to
/// be new. Likewise, if the object's data has been deleted from the database
/// then the object is considered to be new.
/// </remarks>
/// <returns>A value indicating if this object is new.</returns>
bool IsNew { get;}
/// <summary>
/// Returns <see langword="true" /> if this object is both dirty and valid.
/// </summary>
/// <remarks>
/// An object is considered dirty (changed) if
/// <see cref="P:Csla.BusinessBase.IsDirty" /> returns <see langword="true" />. It is
/// considered valid if IsValid
/// returns <see langword="true" />. The IsSavable property is
/// a combination of these two properties.
/// </remarks>
/// <returns>A value indicating if this object is both dirty and valid.</returns>
bool IsSavable { get;}
/// <summary>
/// For internal use only!!
/// </summary>
/// <remarks>
/// Altering this value will almost certainly
/// break your code. This property is for use
/// by the parent collection only!
/// </remarks>
int EditLevelAdded { get; set;}
/// <summary>
/// Gets the current edit level of the object.
/// </summary>
int EditLevel { get; }
/// <summary>
/// Called by a parent object to mark the child
/// for deferred deletion.
/// </summary>
void DeleteChild();
/// <summary>
/// Used by BusinessListBase as a child object is
/// created to tell the child object about its
/// parent.
/// </summary>
/// <param name="parent">A reference to the parent collection object.</param>
void SetParent(IParent parent);
/// <summary>
/// Marks the object for deletion. The object will be deleted as part of the
/// next save operation.
/// </summary>
void Delete();
}
}

View File

@@ -0,0 +1,24 @@
namespace Csla.Core
{
/// <summary>
/// Defines the common methods required by all
/// editable CSLA collection objects.
/// </summary>
/// <remarks>
/// It is strongly recommended that the implementations
/// of the methods in this interface be made Private
/// so as to not clutter up the native interface of
/// the collection objects.
/// </remarks>
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming",
"CA1711:IdentifiersShouldNotHaveIncorrectSuffix")]
public interface IEditableCollection : IUndoableObject
{
/// <summary>
/// Removes the specified child from the parent
/// collection.
/// </summary>
/// <param name="child">Child object to be removed.</param>
void RemoveChild(Core.IEditableBusinessObject child);
}
}

View File

@@ -0,0 +1,18 @@
using System;
using System.ComponentModel;
namespace Csla.Core
{
/// <summary>
/// Extends <see cref="IBindingList" /> by adding extra
/// events.
/// </summary>
public interface IExtendedBindingList : IBindingList
{
/// <summary>
/// Event indicating that an item is being
/// removed from the list.
/// </summary>
event EventHandler<RemovingItemEventArgs> RemovingItem;
}
}

View File

@@ -0,0 +1,26 @@
using System;
namespace Csla.Core
{
/// <summary>
/// Defines the interface that must be implemented
/// by any business object that contains child
/// objects.
/// </summary>
public interface IParent
{
/// <summary>
/// This method is called by a child object when it
/// wants to be removed from the collection.
/// </summary>
/// <param name="child">The child object to remove.</param>
void RemoveChild(Core.IEditableBusinessObject child);
/// <summary>
/// Override this method to be notified when a child object's
/// <see cref="Core.BusinessBase.ApplyEdit" /> method has
/// completed.
/// </summary>
/// <param name="child">The child object that was edited.</param>
void ApplyEditChild(Core.IEditableBusinessObject child);
}
}

View File

@@ -0,0 +1,14 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Csla.Core
{
/// <summary>
/// Interface implemented by all read-only collection
/// classes.
/// </summary>
public interface IReadOnlyCollection : IBusinessObject
{
}
}

View File

@@ -0,0 +1,16 @@
namespace Csla.Core
{
/// <summary>
/// Specifies that the object is a readonly
/// business object.
/// </summary>
public interface IReadOnlyObject : IBusinessObject
{
/// <summary>
/// Returns <see langword="true" /> if the user is allowed to read the
/// calling property.
/// </summary>
/// <param name="propertyName">Name of the property to read.</param>
bool CanReadProperty(string propertyName);
}
}

View File

@@ -0,0 +1,31 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Csla.Core
{
/// <summary>
/// Implement this interface in a collection
/// to report a total row count to
/// <see cref="Csla.Web.CslaDataSource"/>, where that
/// row count is different from the collection's
/// normal Count property value.
/// </summary>
/// <remarks>
/// This interface is used to provide paging
/// support for web data binding through
/// <see cref="Csla.Web.CslaDataSource"/>. You should
/// implement this interface in your business
/// collection class, along with windowed
/// data loading, to provide efficient paging
/// support.
/// </remarks>
public interface IReportTotalRowCount
{
/// <summary>
/// The total number of rows of available
/// data.
/// </summary>
int TotalRowCount { get;}
}
}

View File

@@ -0,0 +1,23 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Csla.Core
{
/// <summary>
/// Specifies that the object can save
/// itself.
/// </summary>
public interface ISavable
{
/// <summary>
/// Saves the object to the database.
/// </summary>
/// <returns>A new object containing the saved values.</returns>
object Save();
/// <summary>
/// Event raised when an object has been saved.
/// </summary>
event EventHandler<SavedEventArgs> Saved;
}
}

View File

@@ -0,0 +1,40 @@
namespace Csla.Core
{
/// <summary>
/// Defines the methods required to participate
/// in n-level undo within the CSLA .NET framework.
/// </summary>
/// <remarks>
/// This interface is used by Csla.Core.UndoableBase
/// to initiate begin, cancel and apply edit operations.
/// </remarks>
public interface IUndoableObject : IBusinessObject
{
/// <summary>
/// Copies the state of the object and places the copy
/// onto the state stack.
/// </summary>
void CopyState();
/// <summary>
/// Restores the object's state to the most recently
/// copied values from the state stack.
/// </summary>
/// <remarks>
/// Restores the state of the object to its
/// previous value by taking the data out of
/// the stack and restoring it into the fields
/// of the object.
/// </remarks>
void UndoChanges();
/// <summary>
/// Accepts any changes made to the object since the last
/// state copy was made.
/// </summary>
/// <remarks>
/// The most recent state copy is removed from the state
/// stack and discarded, thus committing any changes made
/// to the object's state.
/// </remarks>
void AcceptChanges();
}
}

View File

@@ -0,0 +1,29 @@
using System;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
namespace Csla.Core
{
internal static class ObjectCloner
{
/// <summary>
/// Clones an object by using the
/// <see cref="BinaryFormatter" />.
/// </summary>
/// <param name="obj">The object to clone.</param>
/// <remarks>
/// The object to be cloned must be serializable.
/// </remarks>
public static object Clone(object obj)
{
using (MemoryStream buffer = new MemoryStream())
{
BinaryFormatter formatter = new BinaryFormatter();
formatter.Serialize(buffer, obj);
buffer.Position = 0;
object temp = formatter.Deserialize(buffer);
return temp;
}
}
}
}

View File

@@ -0,0 +1,123 @@
using System;
using Csla.Properties;
namespace Csla.Core
{
/// <summary>
/// A readonly version of BindingList(Of T)
/// </summary>
/// <typeparam name="C">Type of item contained in the list.</typeparam>
/// <remarks>
/// This is a subclass of BindingList(Of T) that implements
/// a readonly list, preventing adding and removing of items
/// from the list. Use the IsReadOnly property
/// to unlock the list for loading/unloading data.
/// </remarks>
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming",
"CA1710:IdentifiersShouldHaveCorrectSuffix")]
[Serializable()]
public abstract class ReadOnlyBindingList<C> :
Core.ExtendedBindingList<C>, Core.IBusinessObject
{
private bool _isReadOnly = true;
/// <summary>
/// Gets or sets a value indicating whether the list is readonly.
/// </summary>
/// <remarks>
/// Subclasses can set this value to unlock the collection
/// in order to alter the collection's data.
/// </remarks>
/// <value>True indicates that the list is readonly.</value>
public bool IsReadOnly
{
get { return _isReadOnly; }
protected set { _isReadOnly = value; }
}
/// <summary>
/// Creates an instance of the object.
/// </summary>
protected ReadOnlyBindingList()
{
this.RaiseListChangedEvents = false;
AllowEdit = false;
AllowRemove = false;
AllowNew = false;
this.RaiseListChangedEvents = true;
}
/// <summary>
/// Prevents clearing the collection.
/// </summary>
protected override void ClearItems()
{
if (!IsReadOnly)
{
bool oldValue = AllowRemove;
AllowRemove = true;
base.ClearItems();
AllowRemove = oldValue;
}
else
throw new NotSupportedException(Resources.ClearInvalidException);
}
/// <summary>
/// Prevents insertion of items into the collection.
/// </summary>
protected override object AddNewCore()
{
if (!IsReadOnly)
return base.AddNewCore();
else
throw new NotSupportedException(Resources.InsertInvalidException);
}
/// <summary>
/// Prevents insertion of items into the collection.
/// </summary>
/// <param name="index">Index at which to insert the item.</param>
/// <param name="item">Item to insert.</param>
protected override void InsertItem(int index, C item)
{
if (!IsReadOnly)
base.InsertItem(index, item);
else
throw new NotSupportedException(Resources.InsertInvalidException);
}
/// <summary>
/// Removes the item at the specified index if the collection is
/// not in readonly mode.
/// </summary>
/// <param name="index">Index of the item to remove.</param>
protected override void RemoveItem(int index)
{
if (!IsReadOnly)
{
bool oldValue = AllowRemove;
AllowRemove = true;
base.RemoveItem(index);
AllowRemove = oldValue;
}
else
throw new NotSupportedException(Resources.RemoveInvalidException);
}
/// <summary>
/// Replaces the item at the specified index with the
/// specified item if the collection is not in
/// readonly mode.
/// </summary>
/// <param name="index">Index of the item to replace.</param>
/// <param name="item">New item for the list.</param>
protected override void SetItem(int index, C item)
{
if (!IsReadOnly)
base.SetItem(index, item);
else
throw new NotSupportedException(Resources.ChangeInvalidException);
}
}
}

View File

@@ -0,0 +1,36 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Csla.Core
{
/// <summary>
/// Contains event data for the RemovingItem
/// event.
/// </summary>
public class RemovingItemEventArgs : EventArgs
{
private object _removingItem;
/// <summary>
/// Gets a reference to the item that was
/// removed from the list.
/// </summary>
public object RemovingItem
{
get { return _removingItem; }
}
/// <summary>
/// Create an instance of the object.
/// </summary>
/// <param name="removingItem">
/// A reference to the item that was
/// removed from the list.
/// </param>
public RemovingItemEventArgs(object removingItem)
{
_removingItem = removingItem;
}
}
}

View File

@@ -0,0 +1,36 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Csla.Core
{
/// <summary>
/// Event arguments containing a reference
/// to the new object that was returned
/// as a result of the Save() operation.
/// </summary>
public class SavedEventArgs : EventArgs
{
private object _newObject;
/// <summary>
/// Gets the object that was returned
/// as a result of the Save() operation.
/// </summary>
public object NewObject
{
get { return _newObject; }
}
/// <summary>
/// Creates an instance of the object.
/// </summary>
/// <param name="newObject">
/// The object that was returned as a
/// result of the Save() operation.
/// </param>
public SavedEventArgs(object newObject)
{
_newObject = newObject;
}
}
}

View File

@@ -0,0 +1,296 @@
using System;
using System.Collections;
using System.Collections.Specialized;
using System.Collections.Generic;
using System.Reflection;
using System.IO;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
using System.ComponentModel;
namespace Csla.Core
{
/// <summary>
/// Implements n-level undo capabilities as
/// described in Chapters 2 and 3.
/// </summary>
[Serializable()]
public abstract class UndoableBase : Csla.Core.BindableBase, Csla.Core.IUndoableObject
{
// keep a stack of object state values.
[NotUndoable()]
private Stack<byte[]> _stateStack = new Stack<byte[]>();
/// <summary>
/// Creates an instance of the object.
/// </summary>
protected UndoableBase()
{
}
/// <summary>
/// Returns the current edit level of the object.
/// </summary>
[EditorBrowsable(EditorBrowsableState.Never)]
protected int EditLevel
{
get { return _stateStack.Count; }
}
void IUndoableObject.CopyState()
{
CopyState();
}
void IUndoableObject.UndoChanges()
{
UndoChanges();
}
void IUndoableObject.AcceptChanges()
{
AcceptChanges();
}
/// <summary>
/// This method is invoked after the CopyState
/// operation is complete.
/// </summary>
[EditorBrowsable(EditorBrowsableState.Advanced)]
protected virtual void CopyStateComplete()
{
}
/// <summary>
/// Copies the state of the object and places the copy
/// onto the state stack.
/// </summary>
[EditorBrowsable(EditorBrowsableState.Never)]
protected internal void CopyState()
{
Type currentType = this.GetType();
HybridDictionary state = new HybridDictionary();
FieldInfo[] fields;
do
{
// get the list of fields in this type
fields = currentType.GetFields(
BindingFlags.NonPublic |
BindingFlags.Instance |
BindingFlags.Public);
foreach (FieldInfo field in fields)
{
// make sure we process only our variables
if (field.DeclaringType == currentType)
{
// see if this field is marked as not undoable
if (!NotUndoableField(field))
{
// the field is undoable, so it needs to be processed.
object value = field.GetValue(this);
if (typeof(Csla.Core.IUndoableObject).IsAssignableFrom(field.FieldType))
{
// make sure the variable has a value
if (value == null)
{
// variable has no value - store that fact
state.Add(GetFieldName(field), null);
}
else
{
// this is a child object, cascade the call
((Core.IUndoableObject)value).CopyState();
}
}
else
{
// this is a normal field, simply trap the value
state.Add(GetFieldName(field), value);
}
}
}
}
currentType = currentType.BaseType;
} while (currentType != typeof(UndoableBase));
// serialize the state and stack it
using (MemoryStream buffer = new MemoryStream())
{
BinaryFormatter formatter = new BinaryFormatter();
formatter.Serialize(buffer, state);
_stateStack.Push(buffer.ToArray());
}
CopyStateComplete();
}
/// <summary>
/// This method is invoked after the UndoChanges
/// operation is complete.
/// </summary>
[EditorBrowsable(EditorBrowsableState.Advanced)]
protected virtual void UndoChangesComplete()
{
}
/// <summary>
/// Restores the object's state to the most recently
/// copied values from the state stack.
/// </summary>
/// <remarks>
/// Restores the state of the object to its
/// previous value by taking the data out of
/// the stack and restoring it into the fields
/// of the object.
/// </remarks>
[EditorBrowsable(EditorBrowsableState.Never)]
protected internal void UndoChanges()
{
// if we are a child object we might be asked to
// undo below the level where stacked states,
// so just do nothing in that case
if (EditLevel > 0)
{
HybridDictionary state;
using (MemoryStream buffer = new MemoryStream(_stateStack.Pop()))
{
buffer.Position = 0;
BinaryFormatter formatter = new BinaryFormatter();
state = (HybridDictionary)formatter.Deserialize(buffer);
}
Type currentType = this.GetType();
FieldInfo[] fields;
do
{
// get the list of fields in this type
fields = currentType.GetFields(
BindingFlags.NonPublic |
BindingFlags.Instance |
BindingFlags.Public);
foreach (FieldInfo field in fields)
{
// make sure we process only our variables
if (field.DeclaringType == currentType)
{
// see if the field is undoable or not
if (!NotUndoableField(field))
{
// the field is undoable, so restore its value
object value = field.GetValue(this);
if (typeof(Csla.Core.IUndoableObject).IsAssignableFrom(field.FieldType))
{
// this is a child object
// see if the previous value was empty
if (state.Contains(GetFieldName(field)))
{
// previous value was empty - restore to empty
field.SetValue(this, null);
}
else
{
// make sure the variable has a value
if (value != null)
{
// this is a child object, cascade the call.
((Core.IUndoableObject)value).UndoChanges();
}
}
}
else
{
// this is a regular field, restore its value
field.SetValue(this, state[GetFieldName(field)]);
}
}
}
}
currentType = currentType.BaseType;
} while (currentType != typeof(UndoableBase));
}
UndoChangesComplete();
}
/// <summary>
/// This method is invoked after the AcceptChanges
/// operation is complete.
/// </summary>
[EditorBrowsable(EditorBrowsableState.Advanced)]
protected virtual void AcceptChangesComplete()
{
}
/// <summary>
/// Accepts any changes made to the object since the last
/// state copy was made.
/// </summary>
/// <remarks>
/// The most recent state copy is removed from the state
/// stack and discarded, thus committing any changes made
/// to the object's state.
/// </remarks>
[EditorBrowsable(EditorBrowsableState.Never)]
protected internal void AcceptChanges()
{
if (EditLevel > 0)
{
_stateStack.Pop();
Type currentType = this.GetType();
FieldInfo[] fields;
do
{
// get the list of fields in this type
fields = currentType.GetFields(
BindingFlags.NonPublic |
BindingFlags.Instance |
BindingFlags.Public);
foreach (FieldInfo field in fields)
{
// make sure we process only our variables
if (field.DeclaringType == currentType)
{
// see if the field is undoable or not
if (!NotUndoableField(field))
{
// the field is undoable so see if it is a child object
if (typeof(Csla.Core.IUndoableObject).IsAssignableFrom(field.FieldType))
{
object value = field.GetValue(this);
// make sure the variable has a value
if (value != null)
{
// it is a child object so cascade the call
((Core.IUndoableObject)value).AcceptChanges();
}
}
}
}
}
currentType = currentType.BaseType;
} while (currentType != typeof(UndoableBase));
}
AcceptChangesComplete();
}
#region Helper Functions
private static bool NotUndoableField(FieldInfo field)
{
return Attribute.IsDefined(field, typeof(NotUndoableAttribute));
}
private static string GetFieldName(FieldInfo field)
{
return field.DeclaringType.Name + "!" + field.Name;
}
#endregion
}
}