Reorganized the directory structure a bit; Created a new transforming collection for exposing the types in a collection under a different interface; moved Operation and associated classes to a new namespace; Implemented the basics of the SetProgression's observation mechanics
git-svn-id: file:///srv/devel/repo-conversion/nusu@11 d2e56fa2-650e-0410-a79f-9358c0239efd
This commit is contained in:
parent
f38a0bc1ea
commit
cefbc78868
|
@ -69,6 +69,15 @@
|
||||||
<XNAUseContentPipeline>false</XNAUseContentPipeline>
|
<XNAUseContentPipeline>false</XNAUseContentPipeline>
|
||||||
<Name>ObservableCollection</Name>
|
<Name>ObservableCollection</Name>
|
||||||
</Compile>
|
</Compile>
|
||||||
|
<Compile Include="Source\Collections\ObservableCollection.Test.cs">
|
||||||
|
<XNAUseContentPipeline>false</XNAUseContentPipeline>
|
||||||
|
<Name>ObservableCollection.Test</Name>
|
||||||
|
<DependentUpon>ObservableCollection.cs</DependentUpon>
|
||||||
|
</Compile>
|
||||||
|
<Compile Include="Source\Collections\TransformingReadOnlyCollection.cs">
|
||||||
|
<XNAUseContentPipeline>false</XNAUseContentPipeline>
|
||||||
|
<Name>TransformingReadOnlyCollection</Name>
|
||||||
|
</Compile>
|
||||||
<Compile Include="Source\Collections\UnintrusivePriorityQueue.cs">
|
<Compile Include="Source\Collections\UnintrusivePriorityQueue.cs">
|
||||||
<XNAUseContentPipeline>false</XNAUseContentPipeline>
|
<XNAUseContentPipeline>false</XNAUseContentPipeline>
|
||||||
<Name>UnintrusivePriorityQueue</Name>
|
<Name>UnintrusivePriorityQueue</Name>
|
||||||
|
@ -127,15 +136,19 @@
|
||||||
<XNAUseContentPipeline>false</XNAUseContentPipeline>
|
<XNAUseContentPipeline>false</XNAUseContentPipeline>
|
||||||
<Name>BinarySerializer</Name>
|
<Name>BinarySerializer</Name>
|
||||||
</Compile>
|
</Compile>
|
||||||
<Compile Include="Source\Tracking\IAbortable.cs">
|
<Compile Include="Source\Scheduling\IAbortable.cs">
|
||||||
<XNAUseContentPipeline>false</XNAUseContentPipeline>
|
<XNAUseContentPipeline>false</XNAUseContentPipeline>
|
||||||
<Name>IAbortable</Name>
|
<Name>IAbortable</Name>
|
||||||
</Compile>
|
</Compile>
|
||||||
|
<Compile Include="Source\Tracking\Internal\ObservedProgression.cs">
|
||||||
|
<XNAUseContentPipeline>false</XNAUseContentPipeline>
|
||||||
|
<Name>ObservedProgression</Name>
|
||||||
|
</Compile>
|
||||||
<Compile Include="Source\Tracking\SetProgression.cs">
|
<Compile Include="Source\Tracking\SetProgression.cs">
|
||||||
<XNAUseContentPipeline>false</XNAUseContentPipeline>
|
<XNAUseContentPipeline>false</XNAUseContentPipeline>
|
||||||
<Name>SetProgression</Name>
|
<Name>SetProgression</Name>
|
||||||
</Compile>
|
</Compile>
|
||||||
<Compile Include="Source\Tracking\Operation.cs">
|
<Compile Include="Source\Scheduling\Operation.cs">
|
||||||
<XNAUseContentPipeline>false</XNAUseContentPipeline>
|
<XNAUseContentPipeline>false</XNAUseContentPipeline>
|
||||||
<Name>Operation</Name>
|
<Name>Operation</Name>
|
||||||
</Compile>
|
</Compile>
|
||||||
|
@ -143,15 +156,11 @@
|
||||||
<XNAUseContentPipeline>false</XNAUseContentPipeline>
|
<XNAUseContentPipeline>false</XNAUseContentPipeline>
|
||||||
<Name>Progression</Name>
|
<Name>Progression</Name>
|
||||||
</Compile>
|
</Compile>
|
||||||
<Compile Include="Source\Tracking\ProgressionCollection.cs">
|
|
||||||
<XNAUseContentPipeline>false</XNAUseContentPipeline>
|
|
||||||
<Name>ProgressionCollection</Name>
|
|
||||||
</Compile>
|
|
||||||
<Compile Include="Source\Tracking\ProgressUpdateEventArgs.cs">
|
<Compile Include="Source\Tracking\ProgressUpdateEventArgs.cs">
|
||||||
<XNAUseContentPipeline>false</XNAUseContentPipeline>
|
<XNAUseContentPipeline>false</XNAUseContentPipeline>
|
||||||
<Name>ProgressUpdateEventArgs</Name>
|
<Name>ProgressUpdateEventArgs</Name>
|
||||||
</Compile>
|
</Compile>
|
||||||
<Compile Include="Source\Tracking\ThreadedMethodOperation.cs">
|
<Compile Include="Source\Scheduling\ThreadedMethodOperation.cs">
|
||||||
<XNAUseContentPipeline>false</XNAUseContentPipeline>
|
<XNAUseContentPipeline>false</XNAUseContentPipeline>
|
||||||
<Name>ThreadedMethodOperation</Name>
|
<Name>ThreadedMethodOperation</Name>
|
||||||
</Compile>
|
</Compile>
|
||||||
|
@ -159,9 +168,9 @@
|
||||||
<XNAUseContentPipeline>false</XNAUseContentPipeline>
|
<XNAUseContentPipeline>false</XNAUseContentPipeline>
|
||||||
<Name>WeightedProgression</Name>
|
<Name>WeightedProgression</Name>
|
||||||
</Compile>
|
</Compile>
|
||||||
<Compile Include="Source\Tracking\WeightedProgressionCollection.cs">
|
<Compile Include="Source\Tracking\Internal\WeightedProgressionWrapperCollection.cs">
|
||||||
<XNAUseContentPipeline>false</XNAUseContentPipeline>
|
<XNAUseContentPipeline>false</XNAUseContentPipeline>
|
||||||
<Name>WeightedProgressionCollection</Name>
|
<Name>WeightedProgressionWrapperCollection</Name>
|
||||||
</Compile>
|
</Compile>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
|
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
|
||||||
|
|
105
Source/Collections/ObservableCollection.Test.cs
Normal file
105
Source/Collections/ObservableCollection.Test.cs
Normal file
|
@ -0,0 +1,105 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
#if UNITTEST
|
||||||
|
|
||||||
|
using NUnit.Framework;
|
||||||
|
using NMock2;
|
||||||
|
|
||||||
|
namespace Nuclex.Support.Collections {
|
||||||
|
|
||||||
|
/// <summary>Unit Test for the observable collection class</summary>
|
||||||
|
[TestFixture]
|
||||||
|
public class ObservableCollectionTest {
|
||||||
|
|
||||||
|
/// <summary>Interface used to test the observable collection.</summary>
|
||||||
|
public interface IObservableCollectionSubscriber {
|
||||||
|
|
||||||
|
/// <summary>Called when the collection is about to clear its contents</summary>
|
||||||
|
/// <param name="sender">Collection that is clearing its contents</param>
|
||||||
|
/// <param name="e">Not used</param>
|
||||||
|
void Clearing(object sender, EventArgs e);
|
||||||
|
|
||||||
|
/// <summary>Called when an item is added to the collection</summary>
|
||||||
|
/// <param name="sender">Collection to which an item is being added</param>
|
||||||
|
/// <param name="e">Contains the item that is being added</param>
|
||||||
|
void ItemAdded(object sender, ObservableCollection<int>.ItemEventArgs e);
|
||||||
|
|
||||||
|
/// <summary>Called when an item is removed from the collection</summary>
|
||||||
|
/// <param name="sender">Collection from which an item is being removed</param>
|
||||||
|
/// <param name="e">Contains the item that is being removed</param>
|
||||||
|
void ItemRemoved(object sender, ObservableCollection<int>.ItemEventArgs e);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Initialization routine executed before each test is run</summary>
|
||||||
|
[SetUp]
|
||||||
|
public void Setup() {
|
||||||
|
this.mockery = new Mockery();
|
||||||
|
|
||||||
|
this.mockedSubscriber = this.mockery.NewMock<IObservableCollectionSubscriber>();
|
||||||
|
|
||||||
|
this.observedCollection = new ObservableCollection<int>();
|
||||||
|
this.observedCollection.Clearing += new EventHandler(this.mockedSubscriber.Clearing);
|
||||||
|
this.observedCollection.ItemAdded +=
|
||||||
|
new EventHandler<ObservableCollection<int>.ItemEventArgs>(
|
||||||
|
this.mockedSubscriber.ItemAdded
|
||||||
|
);
|
||||||
|
this.observedCollection.ItemRemoved +=
|
||||||
|
new EventHandler<ObservableCollection<int>.ItemEventArgs>(
|
||||||
|
this.mockedSubscriber.ItemRemoved
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Tests whether the Clearing event is fired</summary>
|
||||||
|
[Test]
|
||||||
|
public void TestClearingEvent() {
|
||||||
|
|
||||||
|
Expect.Once.On(this.mockedSubscriber).
|
||||||
|
Method("Clearing");
|
||||||
|
|
||||||
|
this.observedCollection.Clear();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Tests whether the ItemAdded event is fired</summary>
|
||||||
|
[Test]
|
||||||
|
public void TestItemAddedEvent() {
|
||||||
|
|
||||||
|
Expect.Once.On(this.mockedSubscriber).
|
||||||
|
Method("ItemAdded").
|
||||||
|
WithAnyArguments();
|
||||||
|
|
||||||
|
this.observedCollection.Add(123);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Tests whether the ItemRemoved event is fired</summary>
|
||||||
|
[Test]
|
||||||
|
public void TestItemRemovedEvent() {
|
||||||
|
|
||||||
|
Expect.Once.On(this.mockedSubscriber).
|
||||||
|
Method("ItemAdded").
|
||||||
|
WithAnyArguments();
|
||||||
|
|
||||||
|
Expect.Once.On(this.mockedSubscriber).
|
||||||
|
Method("ItemRemoved").
|
||||||
|
WithAnyArguments();
|
||||||
|
|
||||||
|
this.observedCollection.Add(123);
|
||||||
|
this.observedCollection.Remove(123);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Mock object factory</summary>
|
||||||
|
private Mockery mockery;
|
||||||
|
/// <summary>The mocked observable collection subscriber</summary>
|
||||||
|
private IObservableCollectionSubscriber mockedSubscriber;
|
||||||
|
/// <summary>An observable collection to which a mock will be subscribed</summary>
|
||||||
|
private ObservableCollection<int> observedCollection;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Nuclex.Support.Collections
|
||||||
|
|
||||||
|
#endif // UNITTEST
|
|
@ -30,6 +30,21 @@ namespace Nuclex.Support.Collections {
|
||||||
|
|
||||||
#endregion // class ItemEventArgs
|
#endregion // class ItemEventArgs
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the ObservableCollection class that is empty.
|
||||||
|
/// </summary>
|
||||||
|
public ObservableCollection() : base() { }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the ObservableCollection class as a wrapper
|
||||||
|
/// for the specified list.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="list">The list that is wrapped by the new collection.</param>
|
||||||
|
/// <exception cref="System.ArgumentNullException">
|
||||||
|
/// List is null.
|
||||||
|
/// </exception>
|
||||||
|
public ObservableCollection(IList<ItemType> list) : base(list) { }
|
||||||
|
|
||||||
/// <summary>Raised when an item has been added to the collection</summary>
|
/// <summary>Raised when an item has been added to the collection</summary>
|
||||||
public event EventHandler<ItemEventArgs> ItemAdded;
|
public event EventHandler<ItemEventArgs> ItemAdded;
|
||||||
/// <summary>Raised when an item is removed from the collection</summary>
|
/// <summary>Raised when an item is removed from the collection</summary>
|
||||||
|
|
|
@ -11,14 +11,20 @@ namespace Nuclex.Support.Collections {
|
||||||
[TestFixture]
|
[TestFixture]
|
||||||
public class PriorityQueueTest {
|
public class PriorityQueueTest {
|
||||||
|
|
||||||
|
/// <summary>Comparer for two floating point values</summary>
|
||||||
private class FloatComparer : IComparer<float> {
|
private class FloatComparer : IComparer<float> {
|
||||||
|
|
||||||
|
/// <summary>The default instance of this comparer</summary>
|
||||||
|
public static readonly FloatComparer Default = new FloatComparer();
|
||||||
|
|
||||||
|
/// <summary>Compares two floating points against each other</summary>
|
||||||
|
/// <param name="left">First float to compare</param>
|
||||||
|
/// <param name="right">Second float to compare</param>
|
||||||
|
/// <returns>The relationship of the two floats to each other</returns>
|
||||||
public int Compare(float left, float right) {
|
public int Compare(float left, float right) {
|
||||||
return Math.Sign(left - right);
|
return Math.Sign(left - right);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static readonly FloatComparer Default = new FloatComparer();
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>Tests to ensure the count property is properly updated</summary>
|
/// <summary>Tests to ensure the count property is properly updated</summary>
|
||||||
|
|
|
@ -27,7 +27,7 @@ namespace Nuclex.Support.Collections {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Ensures that the ring buffer still accepts write attempts what would fill the
|
/// Ensures that the ring buffer still accepts write attempts that would fill the
|
||||||
/// entire buffer in one go.
|
/// entire buffer in one go.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Test]
|
[Test]
|
||||||
|
|
664
Source/Collections/TransformingReadOnlyCollection.cs
Normal file
664
Source/Collections/TransformingReadOnlyCollection.cs
Normal file
|
@ -0,0 +1,664 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Collections.ObjectModel;
|
||||||
|
using System.Threading;
|
||||||
|
|
||||||
|
namespace Nuclex.Support.Collections {
|
||||||
|
|
||||||
|
/// <summary>Collection transforming the contents of another collection.</summary>
|
||||||
|
/// <typeparam name="ContainedItemType">
|
||||||
|
/// Type of the items contained in the wrapped collection.
|
||||||
|
/// </typeparam>
|
||||||
|
/// <typeparam name="ExposedItemType">
|
||||||
|
/// Type this collection exposes its items as.
|
||||||
|
/// </typeparam>
|
||||||
|
public abstract class TransformingReadOnlyCollection<ContainedItemType, ExposedItemType> :
|
||||||
|
IList<ExposedItemType>, IList {
|
||||||
|
|
||||||
|
#region class TransformingEnumerator
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// An enumerator that transforms the items returned by an enumerator of the
|
||||||
|
/// wrapped collection into the exposed type on-the-fly.
|
||||||
|
/// </summary>
|
||||||
|
private class TransformingEnumerator : IEnumerator<ExposedItemType> {
|
||||||
|
|
||||||
|
/// <summary>Initializes a new transforming enumerator</summary>
|
||||||
|
/// <param name="transformer">Owner; used to invoke the Transform() method</param>
|
||||||
|
/// <param name="containedTypeEnumerator">Enumerator of the wrapped collection</param>
|
||||||
|
public TransformingEnumerator(
|
||||||
|
TransformingReadOnlyCollection<ContainedItemType, ExposedItemType> transformer,
|
||||||
|
IEnumerator<ContainedItemType> containedTypeEnumerator
|
||||||
|
) {
|
||||||
|
this.transformer = transformer;
|
||||||
|
this.containedTypeEnumerator = containedTypeEnumerator;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Immediately releases all resources used by the instance</summary>
|
||||||
|
public void Dispose() {
|
||||||
|
this.containedTypeEnumerator.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The element in the collection at the current position of the enumerator.
|
||||||
|
/// </summary>
|
||||||
|
public ExposedItemType Current {
|
||||||
|
get {
|
||||||
|
return this.transformer.Transform(this.containedTypeEnumerator.Current);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Gets the current element in the collection.</summary>
|
||||||
|
/// <returns>The current element in the collection.</returns>
|
||||||
|
/// <exception cref="System.InvalidOperationException">
|
||||||
|
/// The enumerator is positioned before the first element of the collection
|
||||||
|
/// or after the last element.
|
||||||
|
/// </exception>
|
||||||
|
public bool MoveNext() {
|
||||||
|
return this.containedTypeEnumerator.MoveNext();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sets the enumerator to its initial position, which is before the first element
|
||||||
|
/// in the collection.
|
||||||
|
/// </summary>
|
||||||
|
/// <exception cref="System.InvalidOperationException">
|
||||||
|
/// The collection was modified after the enumerator was created.
|
||||||
|
/// </exception>
|
||||||
|
public void Reset() {
|
||||||
|
this.containedTypeEnumerator.Reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>The current element in the collection.</summary>
|
||||||
|
/// <exception cref="System.InvalidOperationException">
|
||||||
|
/// The enumerator is positioned before the first element of the collection
|
||||||
|
/// or after the last element.
|
||||||
|
/// </exception>
|
||||||
|
object IEnumerator.Current {
|
||||||
|
get { return Current; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Collection that owns this enumerator; required to invoke the item
|
||||||
|
/// transformation method.
|
||||||
|
/// </summary>
|
||||||
|
private TransformingReadOnlyCollection<ContainedItemType, ExposedItemType> transformer;
|
||||||
|
/// <summary>An enumerator from the wrapped collection</summary>
|
||||||
|
private IEnumerator<ContainedItemType> containedTypeEnumerator;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion // class TransformingEnumerator
|
||||||
|
|
||||||
|
/// <summary>Initializes a new transforming collection wrapper</summary>
|
||||||
|
/// <param name="items">
|
||||||
|
/// Internal list of items that are transformed into the exposed type when
|
||||||
|
/// accessed through the TransformingReadOnlyCollection.
|
||||||
|
/// </param>
|
||||||
|
public TransformingReadOnlyCollection(IList<ContainedItemType> items) {
|
||||||
|
this.items = items;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Determines whether an element is in the TransformingReadOnlyCollection
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="item">
|
||||||
|
/// The object to locate in the TransformingReadOnlyCollection.
|
||||||
|
/// The value can be null for reference types.
|
||||||
|
/// </param>
|
||||||
|
/// <returns>
|
||||||
|
/// True if value is found in the TransformingReadOnlyCollection; otherwise, false.
|
||||||
|
/// </returns>
|
||||||
|
/// <remarks>
|
||||||
|
/// The default implementation of this method is very unoptimized and will
|
||||||
|
/// enumerate all the items in the collection, transforming one after another
|
||||||
|
/// to check whether the transformed item matches the item the user was
|
||||||
|
/// looking for. It is recommended to provide a custom implementation of
|
||||||
|
/// this method, if possible.
|
||||||
|
/// </remarks>
|
||||||
|
public virtual bool Contains(ExposedItemType item) {
|
||||||
|
return (IndexOf(item) != -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Copies the entire TransformingReadOnlyCollection to a compatible one-dimensional
|
||||||
|
/// System.Array, starting at the specified index of the target array.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="array">
|
||||||
|
/// The one-dimensional System.Array that is the destination of the elements copied
|
||||||
|
/// from the TransformingReadOnlyCollection. The System.Array must have
|
||||||
|
/// zero-based indexing.
|
||||||
|
/// </param>
|
||||||
|
/// <param name="index">
|
||||||
|
/// The zero-based index in array at which copying begins.
|
||||||
|
/// </param>
|
||||||
|
/// <exception cref="System.ArgumentException">
|
||||||
|
/// Index is equal to or greater than the length of array or the number of elements
|
||||||
|
/// in the source TransformingReadOnlyCollection is greater than the available space
|
||||||
|
/// from index to the end of the destination array.
|
||||||
|
/// </exception>
|
||||||
|
/// <exception cref="System.ArgumentOutOfRangeException">
|
||||||
|
/// Index is less than zero.
|
||||||
|
/// </exception>
|
||||||
|
/// <exception cref="System.ArgumentNullException">
|
||||||
|
/// Array is null.
|
||||||
|
/// </exception>
|
||||||
|
public void CopyTo(ExposedItemType[] array, int index) {
|
||||||
|
|
||||||
|
if(this.items.Count > (array.Length - index))
|
||||||
|
throw new ArgumentException(
|
||||||
|
"Array too small to fit the collection items starting at the specified index"
|
||||||
|
);
|
||||||
|
|
||||||
|
for(int itemIndex = 0; itemIndex < this.items.Count; ++itemIndex)
|
||||||
|
array[itemIndex + index] = Transform(this.items[itemIndex]);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns an enumerator that iterates through the TransformingReadOnlyCollection.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>
|
||||||
|
/// An enumerator or the TransformingReadOnlyCollection.
|
||||||
|
/// </returns>
|
||||||
|
public IEnumerator<ExposedItemType> GetEnumerator() {
|
||||||
|
return new TransformingEnumerator(this, this.items.GetEnumerator());
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Searches for the specified object and returns the zero-based index of the
|
||||||
|
/// first occurrence within the entire TransformingReadOnlyCollection.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="item">
|
||||||
|
/// The object to locate in the TransformingReadOnlyCollection. The value can
|
||||||
|
/// be null for reference types.
|
||||||
|
/// </param>
|
||||||
|
/// <returns>
|
||||||
|
/// The zero-based index of the first occurrence of item within the entire
|
||||||
|
/// TransformingReadOnlyCollection, if found; otherwise, -1.
|
||||||
|
/// </returns>
|
||||||
|
/// <remarks>
|
||||||
|
/// The default implementation of this method is very unoptimized and will
|
||||||
|
/// enumerate all the items in the collection, transforming one after another
|
||||||
|
/// to check whether the transformed item matches the item the user was
|
||||||
|
/// looking for. It is recommended to provide a custom implementation of
|
||||||
|
/// this method, if possible.
|
||||||
|
/// </remarks>
|
||||||
|
public int IndexOf(ExposedItemType item) {
|
||||||
|
|
||||||
|
if(item == null) {
|
||||||
|
|
||||||
|
for(int index = 0; index < this.items.Count; ++index) {
|
||||||
|
if(Transform(this.items[index]) == null) {
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
EqualityComparer<ExposedItemType> comparer =
|
||||||
|
EqualityComparer<ExposedItemType>.Default;
|
||||||
|
|
||||||
|
for(int index = 0; index < this.items.Count; ++index) {
|
||||||
|
if(comparer.Equals(Transform(this.items[index]), item)) {
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The number of elements contained in the TransformingReadOnlyCollection instance
|
||||||
|
/// </summary>
|
||||||
|
public int Count {
|
||||||
|
get { return this.items.Count; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Gets the element at the specified index.</summary>
|
||||||
|
/// <param name="index">The zero-based index of the element to get.</param>
|
||||||
|
/// <returns>The element at the specified index.</returns>
|
||||||
|
/// <exception cref="System.ArgumentOutOfRangeException">
|
||||||
|
/// Index is less than zero or index is equal to or greater than
|
||||||
|
/// TransformingReadOnlyCollection.Count.
|
||||||
|
/// </exception>
|
||||||
|
public ExposedItemType this[int index] {
|
||||||
|
get { return Transform(this.items[index]); }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Transforms an item into the exposed type</summary>
|
||||||
|
/// <param name="item">Item to be transformed</param>
|
||||||
|
/// <returns>The transformed item</returns>
|
||||||
|
/// <remarks>
|
||||||
|
/// This method is used to transform an item in the wrapped collection into
|
||||||
|
/// the exposed item type whenever the user accesses an item. Expect it to
|
||||||
|
/// be called frequently, because the TransformingReadOnlyCollection does
|
||||||
|
/// not cache otherwise store the transformed items.
|
||||||
|
/// </remarks>
|
||||||
|
protected abstract ExposedItemType Transform(ContainedItemType item);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Determines whether the object is compatible to the collection's data type.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">Object to check for compatibility.</param>
|
||||||
|
/// <returns>
|
||||||
|
/// True if the object is compatible to the collection's data type;
|
||||||
|
/// otherwise false.
|
||||||
|
/// </returns>
|
||||||
|
private static bool IsCompatibleObject(object value) {
|
||||||
|
if(!(value is ExposedItemType)) {
|
||||||
|
if((value != null) || typeof(ExposedItemType).IsValueType) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
#region IList<ExposedItemType> Members
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Determines the index of a specific item in the TransformingReadOnlyCollection.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="item">
|
||||||
|
/// The object to locate in the TransformingReadOnlyCollection.
|
||||||
|
/// </param>
|
||||||
|
/// <returns>
|
||||||
|
/// The index of item if found in the list; otherwise, -1.
|
||||||
|
/// </returns>
|
||||||
|
int IList<ExposedItemType>.IndexOf(ExposedItemType item) {
|
||||||
|
return IndexOf(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Inserts an item to the TransformingReadOnlyCollection at the specified index.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="index">
|
||||||
|
/// The zero-based index at which item should be inserted.
|
||||||
|
/// </param>
|
||||||
|
/// <param name="item">
|
||||||
|
/// The object to insert into the TransformingReadOnlyCollection
|
||||||
|
/// </param>
|
||||||
|
/// <exception cref="System.NotSupportedException">
|
||||||
|
/// The TransformingReadOnlyCollection is read-only.
|
||||||
|
/// </exception>
|
||||||
|
/// <exception cref="System.ArgumentOutOfRangeException">
|
||||||
|
/// index is not a valid index in the TransformingReadOnlyCollection.
|
||||||
|
/// </exception>
|
||||||
|
void IList<ExposedItemType>.Insert(int index, ExposedItemType item) {
|
||||||
|
throw new NotSupportedException("The collection is ready-only");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Removes the TransformingReadOnlyCollection item at the specified index.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="index">The zero-based index of the item to remove.</param>
|
||||||
|
/// <exception cref="System.NotSupportedException">
|
||||||
|
/// The TransformingReadOnlyCollection is read-only.
|
||||||
|
/// </exception>
|
||||||
|
/// <exception cref="System.ArgumentOutOfRangeException">
|
||||||
|
/// Index is not a valid index in the TransformingReadOnlyCollection.
|
||||||
|
/// </exception>
|
||||||
|
void IList<ExposedItemType>.RemoveAt(int index) {
|
||||||
|
throw new NotSupportedException("The collection is ready-only");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Gets or sets the element at the specified index.</summary>
|
||||||
|
/// <param name="index">The zero-based index of the element to get or set.</param>
|
||||||
|
/// <returns>The element at the specified index.</returns>
|
||||||
|
/// <exception cref="System.ArgumentOutOfRangeException">
|
||||||
|
/// Index is not a valid index in the TransformingReadOnlyCollection.
|
||||||
|
/// </exception>
|
||||||
|
/// <exception cref="System.NotSupportedException">
|
||||||
|
/// The property is set and the TransformingReadOnlyCollection is read-only
|
||||||
|
/// </exception>
|
||||||
|
ExposedItemType IList<ExposedItemType>.this[int index] {
|
||||||
|
get {
|
||||||
|
return this[index];
|
||||||
|
}
|
||||||
|
set {
|
||||||
|
throw new NotSupportedException("The collection is ready-only");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region ICollection<ExposedItemType> Members
|
||||||
|
|
||||||
|
/// <summary>Adds an item to the TransformingReadOnlyCollection.</summary>
|
||||||
|
/// <param name="item">The object to add to the TransformingReadOnlyCollection</param>
|
||||||
|
/// <exception cref="System.NotSupportedException">
|
||||||
|
/// The TransformingReadOnlyCollection is read-only.
|
||||||
|
/// </exception>
|
||||||
|
void ICollection<ExposedItemType>.Add(ExposedItemType item) {
|
||||||
|
throw new NotSupportedException("The collection is ready-only");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Removes all items from the TransformingReadOnlyCollection</summary>
|
||||||
|
/// <exception cref="System.NotSupportedException">
|
||||||
|
/// The TransformingReadOnlyCollection is read-only.
|
||||||
|
/// </exception>
|
||||||
|
void ICollection<ExposedItemType>.Clear() {
|
||||||
|
throw new NotSupportedException("The collection is ready-only");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Determines whether the TransformingReadOnlyCollection contains a specific value.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="item">
|
||||||
|
/// The object to locate in the TransformingReadOnlyCollection.
|
||||||
|
/// </param>
|
||||||
|
/// <returns>
|
||||||
|
/// True if item is found in the TransformingReadOnlyCollection; otherwise, false.
|
||||||
|
/// </returns>
|
||||||
|
bool ICollection<ExposedItemType>.Contains(ExposedItemType item) {
|
||||||
|
return Contains(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Copies the elements of the TransformingReadOnlyCollection to an System.Array,
|
||||||
|
/// starting at a particular System.Array index.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="array">
|
||||||
|
/// The one-dimensional System.Array that is the destination of the elements
|
||||||
|
/// copied from TransformingReadOnlyCollection. The System.Array must have
|
||||||
|
/// zero-based indexing.
|
||||||
|
/// </param>
|
||||||
|
/// <param name="arrayIndex">
|
||||||
|
/// The zero-based index in array at which copying begins
|
||||||
|
/// </param>
|
||||||
|
/// <exception cref="System.ArgumentOutOfRangeException">
|
||||||
|
/// ArrayIndex is less than 0.
|
||||||
|
/// </exception>
|
||||||
|
/// <exception cref="System.ArgumentNullException">
|
||||||
|
/// Array is null.
|
||||||
|
/// </exception>
|
||||||
|
/// <exception cref="System.ArgumentException">
|
||||||
|
/// Array is multidimensional or arrayIndex is equal to or greater than the
|
||||||
|
/// length of array or the number of elements in the source
|
||||||
|
/// TransformingReadOnlyCollection is greater than the available
|
||||||
|
/// space from arrayIndex to the end of the destination array or type T cannot
|
||||||
|
/// be cast automatically to the type of the destination array.
|
||||||
|
/// </exception>
|
||||||
|
void ICollection<ExposedItemType>.CopyTo(ExposedItemType[] array, int arrayIndex) {
|
||||||
|
CopyTo(array, arrayIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Removes the first occurrence of a specific object from the
|
||||||
|
/// TransformingReadOnlyCollection.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="item">
|
||||||
|
/// The object to remove from the TransformingReadOnlyCollection
|
||||||
|
/// </param>
|
||||||
|
/// <returns>
|
||||||
|
/// True if item was successfully removed from the TransformingReadOnlyCollection;
|
||||||
|
/// otherwise, false. This method also returns false if item is not found in the
|
||||||
|
/// original TransformingReadOnlyCollection.
|
||||||
|
/// </returns>
|
||||||
|
/// <exception cref="System.NotSupportedException">
|
||||||
|
/// The TransformingReadOnlyCollection is read-only.
|
||||||
|
/// </exception>
|
||||||
|
bool ICollection<ExposedItemType>.Remove(ExposedItemType item) {
|
||||||
|
throw new NotSupportedException("The collection is ready-only");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The number of elements contained in the TransformingReadOnlyCollection.
|
||||||
|
/// </summary>
|
||||||
|
int ICollection<ExposedItemType>.Count {
|
||||||
|
get { return Count; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A value indicating whether the TransformingReadOnlyCollection is read-only.
|
||||||
|
/// </summary>
|
||||||
|
bool ICollection<ExposedItemType>.IsReadOnly {
|
||||||
|
get { return true; }
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region IEnumerable<ExposedItemType> Members
|
||||||
|
|
||||||
|
/// <summary>Returns an enumerator that iterates through the collection.</summary>
|
||||||
|
/// <returns>
|
||||||
|
/// A System.Collections.Generic.IEnumerator<ExposedItemType> that can be used
|
||||||
|
/// to iterate through the collection.
|
||||||
|
/// </returns>
|
||||||
|
IEnumerator<ExposedItemType> IEnumerable<ExposedItemType>.GetEnumerator() {
|
||||||
|
return GetEnumerator();
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region IEnumerable Members
|
||||||
|
|
||||||
|
/// <summary>Returns an enumerator that iterates through a collection.</summary>
|
||||||
|
/// <returns>
|
||||||
|
/// A System.Collections.IEnumerator object that can be used to iterate through
|
||||||
|
/// the collection.
|
||||||
|
/// </returns>
|
||||||
|
IEnumerator IEnumerable.GetEnumerator() {
|
||||||
|
return GetEnumerator();
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region IList Members
|
||||||
|
|
||||||
|
/// <summary>Adds an item to the TransformingReadOnlyCollection.</summary>
|
||||||
|
/// <param name="value">
|
||||||
|
/// The System.Object to add to the TransformingReadOnlyCollection.
|
||||||
|
/// </param>
|
||||||
|
/// <returns>The position into which the new element was inserted.</returns>
|
||||||
|
/// <exception cref="System.NotSupportedException">
|
||||||
|
/// The System.Collections.IList is read-only or the TransformingReadOnlyCollection
|
||||||
|
/// has a fixed size.
|
||||||
|
/// </exception>
|
||||||
|
int IList.Add(object value) {
|
||||||
|
throw new NotSupportedException("The collection is ready-only");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Removes all items from the TransformingReadOnlyCollection.</summary>
|
||||||
|
/// <exception cref="System.NotSupportedException">
|
||||||
|
/// The TransformingReadOnlyCollection is read-only.
|
||||||
|
/// </exception>
|
||||||
|
void IList.Clear() {
|
||||||
|
throw new NotSupportedException("The collection is ready-only");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Determines whether the TransformingReadOnlyCollection contains a specific value.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">
|
||||||
|
/// The System.Object to locate in the TransformingReadOnlyCollection.
|
||||||
|
/// </param>
|
||||||
|
/// <returns>
|
||||||
|
/// True if the System.Object is found in the TransformingReadOnlyCollection;
|
||||||
|
/// otherwise, false.
|
||||||
|
/// </returns>
|
||||||
|
bool IList.Contains(object value) {
|
||||||
|
return Contains((ExposedItemType)value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Determines the index of a specific item in the TransformingReadOnlyCollection.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">
|
||||||
|
/// The System.Object to locate in the TransformingReadOnlyCollection.
|
||||||
|
/// </param>
|
||||||
|
/// <returns>
|
||||||
|
/// The index of value if found in the list; otherwise, -1.
|
||||||
|
/// </returns>
|
||||||
|
int IList.IndexOf(object value) {
|
||||||
|
return IndexOf((ExposedItemType)value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Inserts an item to the TransformingReadOnlyCollection at the specified index.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="index">
|
||||||
|
/// The zero-based index at which value should be inserted.
|
||||||
|
/// </param>
|
||||||
|
/// <param name="value">
|
||||||
|
/// The System.Object to insert into the TransformingReadOnlyCollection.
|
||||||
|
/// </param>
|
||||||
|
/// <exception cref="System.ArgumentOutOfRangeException">
|
||||||
|
/// Index is not a valid index in the TransformingReadOnlyCollection.
|
||||||
|
/// </exception>
|
||||||
|
/// <exception cref="System.NotSupportedException">
|
||||||
|
/// The System.Collections.IList is read-only or the TransformingReadOnlyCollection
|
||||||
|
/// has a fixed size.
|
||||||
|
/// </exception>
|
||||||
|
/// <exception cref="System.NullReferenceException">
|
||||||
|
/// Value is null reference in the TransformingReadOnlyCollection.
|
||||||
|
/// </exception>
|
||||||
|
void IList.Insert(int index, object value) {
|
||||||
|
throw new NotSupportedException("The collection is ready-only");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A value indicating whether the TransformingReadOnlyCollection has a fixed
|
||||||
|
/// size.
|
||||||
|
/// </summary>
|
||||||
|
bool IList.IsFixedSize {
|
||||||
|
get { return true; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A value indicating whether the index is not a valid index in the is read-only.
|
||||||
|
/// </summary>
|
||||||
|
bool IList.IsReadOnly {
|
||||||
|
get { return true; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Removes the first occurrence of a specific object from the
|
||||||
|
/// TransformingReadOnlyCollection.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">
|
||||||
|
/// The System.Object to remove from the TransformingReadOnlyCollection.
|
||||||
|
/// </param>
|
||||||
|
/// <exception cref="System.NotSupportedException">
|
||||||
|
/// The TransformingReadOnlyCollection is read-only or the
|
||||||
|
/// TransformingReadOnlyCollection has a fixed size.
|
||||||
|
/// </exception>
|
||||||
|
void IList.Remove(object value) {
|
||||||
|
throw new NotSupportedException("The collection is ready-only");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Removes the TransformingReadOnlyCollection item at the specified index.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="index">The zero-based index of the item to remove.</param>
|
||||||
|
/// <exception cref="System.ArgumentOutOfRangeException">
|
||||||
|
/// Index is not a valid index in the TransformingReadOnlyCollection.
|
||||||
|
/// </exception>
|
||||||
|
/// <exception cref="System.NotSupportedException">
|
||||||
|
/// The TransformingReadOnlyCollection is read-only or the
|
||||||
|
/// TransformingReadOnlyCollection has a fixed size.
|
||||||
|
/// </exception>
|
||||||
|
void IList.RemoveAt(int index) {
|
||||||
|
throw new NotSupportedException("The collection is ready-only");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Gets or sets the element at the specified index.</summary>
|
||||||
|
/// <param name="index">The zero-based index of the element to get or set.</param>
|
||||||
|
/// <returns>The element at the specified index</returns>
|
||||||
|
/// <exception cref="System.ArgumentOutOfRangeException">
|
||||||
|
/// Index is not a valid index in the TransformingReadOnlyCollection
|
||||||
|
/// </exception>
|
||||||
|
/// <exception cref="System.NotSupportedException">
|
||||||
|
/// The property is set and the TransformingReadOnlyCollection is read-only.
|
||||||
|
/// </exception>
|
||||||
|
object IList.this[int index] {
|
||||||
|
get {
|
||||||
|
return this[index];
|
||||||
|
}
|
||||||
|
set {
|
||||||
|
throw new NotSupportedException("The collection is ready-only");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region ICollection Members
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Copies the elements of the TransformingReadOnlyCollection to an System.Array,
|
||||||
|
/// starting at a particular System.Array index.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="array">
|
||||||
|
/// The one-dimensional System.Array that is the destination of the elements
|
||||||
|
/// copied from TransformingReadOnlyCollection. The System.Array must have zero-based
|
||||||
|
/// indexing.
|
||||||
|
/// </param>
|
||||||
|
/// <param name="index">The zero-based index in array at which copying begins.</param>
|
||||||
|
/// <exception cref="System.ArgumentNullException">
|
||||||
|
/// Array is null.
|
||||||
|
/// </exception>
|
||||||
|
/// <exception cref="System.ArgumentOutOfRangeException">
|
||||||
|
/// Index is less than zero.
|
||||||
|
/// </exception>
|
||||||
|
/// <exception cref="System.ArgumentException">
|
||||||
|
/// Array is multidimensional or index is equal to or greater than the length
|
||||||
|
/// of array or the number of elements in the source TransformingReadOnlyCollection
|
||||||
|
/// is greater than the available space from index to the end of the destination
|
||||||
|
/// array.
|
||||||
|
/// </exception>
|
||||||
|
/// <exception cref="System.InvalidCastException">
|
||||||
|
/// The type of the source TransformingReadOnlyCollection cannot be cast
|
||||||
|
/// automatically to the type of the destination array.
|
||||||
|
/// </exception>
|
||||||
|
void ICollection.CopyTo(Array array, int index) {
|
||||||
|
CopyTo((ExposedItemType[])array, index);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The number of elements contained in the TransformingReadOnlyCollection.
|
||||||
|
/// </summary>
|
||||||
|
int ICollection.Count {
|
||||||
|
get { return Count; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A value indicating whether access to the TransformingReadOnlyCollection
|
||||||
|
/// is synchronized (thread safe).
|
||||||
|
/// </summary>
|
||||||
|
bool ICollection.IsSynchronized {
|
||||||
|
get { return false; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// An object that can be used to synchronize access to the
|
||||||
|
/// TransformingReadOnlyCollection.
|
||||||
|
/// </summary>
|
||||||
|
object ICollection.SyncRoot {
|
||||||
|
get {
|
||||||
|
if(this.syncRoot == null) {
|
||||||
|
ICollection is2 = this.items as ICollection;
|
||||||
|
if(is2 != null) {
|
||||||
|
this.syncRoot = is2.SyncRoot;
|
||||||
|
} else {
|
||||||
|
Interlocked.CompareExchange(ref this.syncRoot, new object(), null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.syncRoot;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
/// <summary>Items being transformed upon exposure by this collection</summary>
|
||||||
|
private IList<ContainedItemType> items;
|
||||||
|
/// <summary>Synchronization root for threaded accesses to this collection</summary>
|
||||||
|
private object syncRoot;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Nuclex.Support.Collections
|
41
Source/Tracking/Internal/ObservedProgression.cs
Normal file
41
Source/Tracking/Internal/ObservedProgression.cs
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace Nuclex.Support.Tracking {
|
||||||
|
|
||||||
|
/// <summary>Progression being observed by another class</summary>
|
||||||
|
/// <typeparam name="ProgressionType">
|
||||||
|
/// Type of the progression that is being observed
|
||||||
|
/// </typeparam>
|
||||||
|
internal class ObservedProgression<ProgressionType>
|
||||||
|
where ProgressionType : Progression {
|
||||||
|
|
||||||
|
/// <summary>Initializes a new observed progression</summary>
|
||||||
|
/// <param name="weightedProgression">Weighted progression being observed</param>
|
||||||
|
internal ObservedProgression(
|
||||||
|
WeightedProgression<ProgressionType> weightedProgression
|
||||||
|
) {
|
||||||
|
this.weightedProgression = weightedProgression;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Weighted progression being observed</summary>
|
||||||
|
public WeightedProgression<ProgressionType> WeightedProgression {
|
||||||
|
get { return this.weightedProgression; }
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
|
||||||
|
internal void AsyncProgressUpdated(object sender, ProgressUpdateEventArgs e) {
|
||||||
|
this.Progress = e.Progress;
|
||||||
|
}
|
||||||
|
internal void AsyncEnded(object sender, EventArgs e) { }
|
||||||
|
*/
|
||||||
|
/// <summary>The weighted progression that is being observed</summary>
|
||||||
|
private WeightedProgression<ProgressionType> weightedProgression;
|
||||||
|
/*
|
||||||
|
/// <summary>Amount of progress this progression has achieved so far</summary>
|
||||||
|
private volatile float progress;
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Nuclex.Support.Tracking
|
|
@ -0,0 +1,60 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Collections.ObjectModel;
|
||||||
|
|
||||||
|
using Nuclex.Support.Collections;
|
||||||
|
|
||||||
|
namespace Nuclex.Support.Tracking {
|
||||||
|
|
||||||
|
/// <summary>Collection of progressions with a weighting value</summary>
|
||||||
|
/// <typeparam name="ProgressionType">Type of progressions to manage</typeparam>
|
||||||
|
/// <remarks>
|
||||||
|
/// <para>
|
||||||
|
/// This collection is exposed as a read-only collection to the user that
|
||||||
|
/// stores WeightedProgressions. Internally, it merely wraps a collection of
|
||||||
|
/// an internal type used to keep track of the individual progression's
|
||||||
|
/// progress in the SetProgression and QueueOperation classes.
|
||||||
|
/// </para>
|
||||||
|
/// <para>
|
||||||
|
/// It is read-only because the design requires a progression to only ever
|
||||||
|
/// finish once. If it was possible eg. to add items after a SetProgression
|
||||||
|
/// had signalled itself as being finished, it would be moved into an
|
||||||
|
/// unfinished state again. Also, an empty SetProgression is, by definition,
|
||||||
|
/// finished (simply because there is no work to do) - unless the contents
|
||||||
|
/// of set are passed to the SetProgression's constructor and never modified
|
||||||
|
/// at all, the design would be violated as soon as ab instance of the
|
||||||
|
/// SetProgression or QueueOperation classes was created.
|
||||||
|
/// </para>
|
||||||
|
/// </remarks>
|
||||||
|
internal class WeightedProgressionCollection<ProgressionType> :
|
||||||
|
TransformingReadOnlyCollection<
|
||||||
|
ObservedProgression<ProgressionType>, WeightedProgression<ProgressionType>
|
||||||
|
>
|
||||||
|
where ProgressionType : Progression {
|
||||||
|
|
||||||
|
/// <summary>Initializes a new weighted progression collection wrapper</summary>
|
||||||
|
/// <param name="items">Items to be exposed as weighted progressions</param>
|
||||||
|
internal WeightedProgressionCollection(
|
||||||
|
IList<ObservedProgression<ProgressionType>> items
|
||||||
|
)
|
||||||
|
: base(items) { }
|
||||||
|
|
||||||
|
/// <summary>Transforms an item into the exposed type</summary>
|
||||||
|
/// <param name="item">Item to be transformed</param>
|
||||||
|
/// <returns>The transformed item</returns>
|
||||||
|
/// <remarks>
|
||||||
|
/// This method is used to transform an item in the wrapped collection into
|
||||||
|
/// the exposed item type whenever the user accesses an item. Expect it to
|
||||||
|
/// be called frequently, because the TransformingReadOnlyCollection does
|
||||||
|
/// not cache otherwise store the transformed items.
|
||||||
|
/// </remarks>
|
||||||
|
protected override WeightedProgression<ProgressionType> Transform(
|
||||||
|
ObservedProgression<ProgressionType> item
|
||||||
|
) {
|
||||||
|
return item.WeightedProgression;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Nuclex.Support.Tracking
|
|
@ -1,16 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Collections.ObjectModel;
|
|
||||||
|
|
||||||
using Nuclex.Support.Collections;
|
|
||||||
|
|
||||||
namespace Nuclex.Support.Tracking {
|
|
||||||
|
|
||||||
/// <summary>Non-generic version of the progression collection</summary>
|
|
||||||
public class ProgressionCollection : ProgressionCollection<Progression> { }
|
|
||||||
|
|
||||||
/// <summary>Generic collection of progressions</summary>
|
|
||||||
public class ProgressionCollection<ProgressionType>
|
|
||||||
: ObservableCollection<Progression> where ProgressionType : Progression { }
|
|
||||||
|
|
||||||
} // namespace Nuclex.Support.Tracking
|
|
|
@ -1,5 +1,6 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Collections.ObjectModel;
|
||||||
|
|
||||||
using Nuclex.Support.Collections;
|
using Nuclex.Support.Collections;
|
||||||
|
|
||||||
|
@ -10,15 +11,31 @@ namespace Nuclex.Support.Tracking {
|
||||||
public class SetProgression<ProgressionType> : Progression
|
public class SetProgression<ProgressionType> : Progression
|
||||||
where ProgressionType : Progression {
|
where ProgressionType : Progression {
|
||||||
|
|
||||||
|
/// <summary>Initializes a new set progression</summary>
|
||||||
// TODO
|
/// <param name="progressions">Progressions to track with this set</param>
|
||||||
|
/// <remarks>
|
||||||
|
/// Uses a default weighting factor of 1.0 for all progressions.
|
||||||
|
/// </remarks>
|
||||||
|
public SetProgression(IEnumerable<ProgressionType> progressions) {
|
||||||
}
|
}
|
||||||
/*
|
|
||||||
public class SetOperation<OperationType> : Operation
|
|
||||||
where OperationType : OperationType
|
|
||||||
|
|
||||||
QueueOperation
|
/// <summary>Initializes a new set progression</summary>
|
||||||
*/
|
/// <param name="progressions">Progressions to track with this set</param>
|
||||||
|
public SetProgression(IEnumerable<WeightedProgression<ProgressionType>> progressions) {
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Childs contained in the progression set</summary>
|
||||||
|
public ReadOnlyCollection<WeightedProgression<ProgressionType>> Childs {
|
||||||
|
get { return null; }
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
/// <summary>Progressions being managed in the set</summary>
|
||||||
|
private ReadOnlyCollection<ProgressionType> progressions;
|
||||||
|
/// <summary>whether the progress needs to be recalculated</summary>
|
||||||
|
private volatile bool needProgressRecalculation;
|
||||||
|
/// <summary>Total progress achieved by the progressions in this collection</summary>
|
||||||
|
private volatile float totalProgress;
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace Nuclex.Support.Tracking
|
} // namespace Nuclex.Support.Tracking
|
||||||
|
|
|
@ -5,36 +5,20 @@ using System.Text;
|
||||||
namespace Nuclex.Support.Tracking {
|
namespace Nuclex.Support.Tracking {
|
||||||
|
|
||||||
/// <summary>Progression with an associated weight for the total progress</summary>
|
/// <summary>Progression with an associated weight for the total progress</summary>
|
||||||
internal class WeightedProgression<ProgressionType> : IDisposable
|
public class WeightedProgression<ProgressionType> where ProgressionType : Progression {
|
||||||
where ProgressionType : Progression {
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new weighted progression with a default weight of 1.0
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="progression">Progression whose progress to monitor</param>
|
||||||
|
public WeightedProgression(ProgressionType progression) : this(progression, 1.0f) { }
|
||||||
|
|
||||||
/// <summary>Initializes a new weighted progression</summary>
|
/// <summary>Initializes a new weighted progression</summary>
|
||||||
/// <param name="callback">Callback to pass progress updates on to</param>
|
|
||||||
/// <param name="progression">Progression whose progress to monitor</param>
|
/// <param name="progression">Progression whose progress to monitor</param>
|
||||||
/// <param name="weight">Weighting of the progression's progress</param>
|
/// <param name="weight">Weighting of the progression's progress</param>
|
||||||
public WeightedProgression(
|
public WeightedProgression(ProgressionType progression, float weight) {
|
||||||
ProgressionType progression,
|
|
||||||
EventHandler<ProgressUpdateEventArgs> callback,
|
|
||||||
float weight
|
|
||||||
) {
|
|
||||||
this.progression = progression;
|
this.progression = progression;
|
||||||
this.weight = weight;
|
this.weight = weight;
|
||||||
this.callback = callback;
|
|
||||||
|
|
||||||
progression.AsyncProgressUpdated += new EventHandler<ProgressUpdateEventArgs>(
|
|
||||||
asyncProgressUpdated
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>Disposes of the resources used by this instance immediately</summary>
|
|
||||||
public void Dispose() {
|
|
||||||
if(this.progression != null) {
|
|
||||||
progression.AsyncProgressUpdated -= new EventHandler<ProgressUpdateEventArgs>(
|
|
||||||
asyncProgressUpdated
|
|
||||||
);
|
|
||||||
this.progression = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>Progression being wrapped by this weighted progression</summary>
|
/// <summary>Progression being wrapped by this weighted progression</summary>
|
||||||
|
@ -42,30 +26,13 @@ namespace Nuclex.Support.Tracking {
|
||||||
get { return this.progression; }
|
get { return this.progression; }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>Progress this progression has achieved so far</summary>
|
/// <summary>The contribution of this progression to the total progress</summary>
|
||||||
public float Progress {
|
|
||||||
get { return this.progress; }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>The weighting of this progression in the total progress</summary>
|
|
||||||
public float Weight {
|
public float Weight {
|
||||||
get { return this.weight; }
|
get { return this.weight; }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>Handles progress reports by the progression</summary>
|
|
||||||
/// <param name="sender">Progression that has made progress</param>
|
|
||||||
/// <param name="e">Contains the currently achieved progress</param>
|
|
||||||
private void asyncProgressUpdated(object sender, ProgressUpdateEventArgs e) {
|
|
||||||
this.progress = e.Progress;
|
|
||||||
this.callback(sender, e);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>Progression whose progress we're tracking</summary>
|
/// <summary>Progression whose progress we're tracking</summary>
|
||||||
private ProgressionType progression;
|
private ProgressionType progression;
|
||||||
/// <summary>Callback to which any progress reports will be passed on</summary>
|
|
||||||
private EventHandler<ProgressUpdateEventArgs> callback;
|
|
||||||
/// <summary>Most recent progress reported by the progression</summary>
|
|
||||||
private volatile float progress;
|
|
||||||
/// <summary>Weighting of this progression in the total progress</summary>
|
/// <summary>Weighting of this progression in the total progress</summary>
|
||||||
private float weight;
|
private float weight;
|
||||||
|
|
||||||
|
|
|
@ -1,13 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Text;
|
|
||||||
|
|
||||||
using Nuclex.Support.Collections;
|
|
||||||
|
|
||||||
namespace Nuclex.Support.Tracking {
|
|
||||||
|
|
||||||
internal class WeightedProgressionCollection<ProgressionType>
|
|
||||||
: ObservableCollection<WeightedProgression<ProgressionType>>
|
|
||||||
where ProgressionType : Progression { }
|
|
||||||
|
|
||||||
} // namespace Nuclex.Support.Tracking
|
|
Loading…
Reference in New Issue
Block a user