Commit for development environment setup
This commit is contained in:
@@ -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
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,10 @@
|
||||
namespace Csla.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// This is the core interface implemented
|
||||
/// by all CSLA .NET base classes.
|
||||
/// </summary>
|
||||
public interface IBusinessObject
|
||||
{
|
||||
}
|
||||
}
|
@@ -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
|
||||
{
|
||||
}
|
||||
}
|
@@ -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();
|
||||
}
|
||||
}
|
@@ -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);
|
||||
}
|
||||
}
|
@@ -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;
|
||||
}
|
||||
}
|
@@ -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);
|
||||
}
|
||||
}
|
@@ -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
|
||||
{
|
||||
}
|
||||
}
|
@@ -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);
|
||||
}
|
||||
}
|
@@ -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;}
|
||||
}
|
||||
}
|
@@ -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;
|
||||
}
|
||||
}
|
@@ -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();
|
||||
}
|
||||
}
|
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
@@ -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
|
||||
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user