SetProgression partially working; wrote several unit tests using the NMock library; lots of smaller improvements to the progression classes
git-svn-id: file:///srv/devel/repo-conversion/nusu@12 d2e56fa2-650e-0410-a79f-9358c0239efd
This commit is contained in:
parent
cefbc78868
commit
71b6dc90a2
|
@ -164,6 +164,11 @@
|
|||
<XNAUseContentPipeline>false</XNAUseContentPipeline>
|
||||
<Name>ThreadedMethodOperation</Name>
|
||||
</Compile>
|
||||
<Compile Include="Source\Tracking\SetProgression.Test.cs">
|
||||
<XNAUseContentPipeline>false</XNAUseContentPipeline>
|
||||
<Name>SetProgression.Test</Name>
|
||||
<DependentUpon>SetProgression.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Source\Tracking\WeightedProgression.cs">
|
||||
<XNAUseContentPipeline>false</XNAUseContentPipeline>
|
||||
<Name>WeightedProgression</Name>
|
||||
|
|
|
@ -49,35 +49,36 @@ namespace Nuclex.Support.Collections {
|
|||
new EventHandler<ObservableCollection<int>.ItemEventArgs>(
|
||||
this.mockedSubscriber.ItemRemoved
|
||||
);
|
||||
|
||||
this.mockery.VerifyAllExpectationsHaveBeenMet();
|
||||
}
|
||||
|
||||
/// <summary>Tests whether the Clearing event is fired</summary>
|
||||
[Test]
|
||||
public void TestClearingEvent() {
|
||||
|
||||
Expect.Once.On(this.mockedSubscriber).
|
||||
Method("Clearing");
|
||||
|
||||
this.observedCollection.Clear();
|
||||
|
||||
this.mockery.VerifyAllExpectationsHaveBeenMet();
|
||||
}
|
||||
|
||||
/// <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);
|
||||
|
||||
this.mockery.VerifyAllExpectationsHaveBeenMet();
|
||||
}
|
||||
|
||||
/// <summary>Tests whether the ItemRemoved event is fired</summary>
|
||||
[Test]
|
||||
public void TestItemRemovedEvent() {
|
||||
|
||||
Expect.Once.On(this.mockedSubscriber).
|
||||
Method("ItemAdded").
|
||||
WithAnyArguments();
|
||||
|
@ -89,6 +90,7 @@ namespace Nuclex.Support.Collections {
|
|||
this.observedCollection.Add(123);
|
||||
this.observedCollection.Remove(123);
|
||||
|
||||
this.mockery.VerifyAllExpectationsHaveBeenMet();
|
||||
}
|
||||
|
||||
/// <summary>Mock object factory</summary>
|
||||
|
|
|
@ -8,34 +8,105 @@ namespace Nuclex.Support.Tracking {
|
|||
/// <typeparam name="ProgressionType">
|
||||
/// Type of the progression that is being observed
|
||||
/// </typeparam>
|
||||
internal class ObservedProgression<ProgressionType>
|
||||
internal class ObservedProgression<ProgressionType> : IDisposable
|
||||
where ProgressionType : Progression {
|
||||
|
||||
/// <summary>Delegate for reporting progress updates</summary>
|
||||
public delegate void ReportDelegate();
|
||||
|
||||
/// <summary>Initializes a new observed progression</summary>
|
||||
/// <param name="weightedProgression">Weighted progression being observed</param>
|
||||
/// <param name="progressUpdateCallback">
|
||||
/// Callback to invoke when the progression's progress changes
|
||||
/// </param>
|
||||
/// <param name="endedCallback">
|
||||
/// Callback to invoke when the progression has ended
|
||||
/// </param>
|
||||
internal ObservedProgression(
|
||||
WeightedProgression<ProgressionType> weightedProgression
|
||||
WeightedProgression<ProgressionType> weightedProgression,
|
||||
ReportDelegate progressUpdateCallback,
|
||||
ReportDelegate endedCallback
|
||||
) {
|
||||
this.weightedProgression = weightedProgression;
|
||||
this.endedCallback = endedCallback;
|
||||
this.progressUpdateCallback = progressUpdateCallback;
|
||||
|
||||
this.weightedProgression.Progression.AsyncEnded +=
|
||||
new EventHandler(asyncEnded);
|
||||
|
||||
this.weightedProgression.Progression.AsyncProgressUpdated +=
|
||||
new EventHandler<ProgressUpdateEventArgs>(asyncProgressUpdated);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>Immediately releases all resources owned by the object</summary>
|
||||
public void Dispose() {
|
||||
disconnectEvents();
|
||||
}
|
||||
|
||||
/// <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;
|
||||
/// <summary>Amount of progress this progression has achieved so far</summary>
|
||||
public float Progress {
|
||||
get { return this.progress; }
|
||||
}
|
||||
internal void AsyncEnded(object sender, EventArgs e) { }
|
||||
*/
|
||||
|
||||
/// <summary>Called when the observed progression has ended</summary>
|
||||
/// <param name="sender">Progression that has ended</param>
|
||||
/// <param name="e">Not used</param>
|
||||
private void asyncEnded(object sender, EventArgs e) {
|
||||
this.progress = 1.0f;
|
||||
|
||||
disconnectEvents(); // We don't need those anymore!
|
||||
|
||||
this.progressUpdateCallback();
|
||||
}
|
||||
|
||||
/// <summary>Called when the progress of the observed progression changes</summary>
|
||||
/// <param name="sender">Progression whose progress has changed</param>
|
||||
/// <param name="e">Contains the updated progress</param>
|
||||
private void asyncProgressUpdated(object sender, ProgressUpdateEventArgs e) {
|
||||
this.progress = e.Progress;
|
||||
|
||||
this.progressUpdateCallback();
|
||||
}
|
||||
|
||||
/// <summary>Unscribes from all events of the observed progression</summary>
|
||||
private void disconnectEvents() {
|
||||
|
||||
// Make use of the double check locking idiom to avoid the costly lock when
|
||||
// the events have already been unsubscribed
|
||||
if(this.endedCallback != null) {
|
||||
|
||||
// This is an internal class with special knowledge that there
|
||||
// is no risk of deadlock involved, so we don't need a fancy syncRoot!
|
||||
lock(this) {
|
||||
if(this.endedCallback != null) {
|
||||
this.weightedProgression.Progression.AsyncEnded -=
|
||||
new EventHandler(asyncEnded);
|
||||
|
||||
this.weightedProgression.Progression.AsyncProgressUpdated -=
|
||||
new EventHandler<ProgressUpdateEventArgs>(asyncProgressUpdated);
|
||||
|
||||
this.endedCallback = null;
|
||||
this.progressUpdateCallback = null;
|
||||
}
|
||||
}
|
||||
|
||||
} // endedCallback != null
|
||||
|
||||
}
|
||||
|
||||
/// <summary>The weighted progression that is being observed</summary>
|
||||
private WeightedProgression<ProgressionType> weightedProgression;
|
||||
/*
|
||||
/// <summary>Amount of progress this progression has achieved so far</summary>
|
||||
/// <summary>Callback to invoke when the progress updates</summary>
|
||||
private volatile ReportDelegate progressUpdateCallback;
|
||||
/// <summary>Callback to invoke when the progression ends</summary>
|
||||
private volatile ReportDelegate endedCallback;
|
||||
/// <summary>Progress achieved so far</summary>
|
||||
private volatile float progress;
|
||||
*/
|
||||
}
|
||||
|
||||
} // namespace Nuclex.Support.Tracking
|
||||
|
|
|
@ -27,7 +27,7 @@ namespace Nuclex.Support.Tracking {
|
|||
/// SetProgression or QueueOperation classes was created.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
internal class WeightedProgressionCollection<ProgressionType> :
|
||||
internal class WeightedProgressionWrapperCollection<ProgressionType> :
|
||||
TransformingReadOnlyCollection<
|
||||
ObservedProgression<ProgressionType>, WeightedProgression<ProgressionType>
|
||||
>
|
||||
|
@ -35,7 +35,7 @@ namespace Nuclex.Support.Tracking {
|
|||
|
||||
/// <summary>Initializes a new weighted progression collection wrapper</summary>
|
||||
/// <param name="items">Items to be exposed as weighted progressions</param>
|
||||
internal WeightedProgressionCollection(
|
||||
internal WeightedProgressionWrapperCollection(
|
||||
IList<ObservedProgression<ProgressionType>> items
|
||||
)
|
||||
: base(items) { }
|
||||
|
|
|
@ -19,7 +19,7 @@ namespace Nuclex.Support.Tracking {
|
|||
}
|
||||
|
||||
/// <summary>Achieved progress</summary>
|
||||
protected float progress;
|
||||
private float progress;
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -52,17 +52,21 @@ namespace Nuclex.Support.Tracking {
|
|||
public event EventHandler AsyncEnded;
|
||||
|
||||
/// <summary>Whether the progression has ended already</summary>
|
||||
public virtual bool Ended {
|
||||
public bool Ended {
|
||||
get { return this.ended; }
|
||||
}
|
||||
|
||||
/// <summary>WaitHandle that can be used to wait for the progression to end</summary>
|
||||
public WaitHandle WaitHandle {
|
||||
get {
|
||||
|
||||
|
||||
// The WaitHandle will only be created when someone asks for it!
|
||||
// See the Double-Check Locking idiom on why the condition is checked twice
|
||||
// (primarily, it avoids an expensive lock when it isn't needed)
|
||||
//
|
||||
// We can *not* optimize this lock away since we absolutely must not create
|
||||
// two doneEvents -- someone might call .WaitOne() on the first one when only
|
||||
// the second one is assigned to this.doneEvent and gets set in the end.
|
||||
if(this.doneEvent == null) {
|
||||
|
||||
lock(this.syncRoot) {
|
||||
|
@ -109,16 +113,27 @@ namespace Nuclex.Support.Tracking {
|
|||
/// seperately.
|
||||
/// </remarks>
|
||||
protected virtual void OnAsyncEnded() {
|
||||
|
||||
// TODO: Find a way around this. Interlocked.Exchange would be best!
|
||||
// We do not lock here since we require this method to be called only once
|
||||
// in the object's lifetime. If someone really badly wanted to break this
|
||||
// he'd probably have a one-in-a-million chance of getting through.
|
||||
if(this.ended)
|
||||
throw new InvalidOperationException("The progression has already been ended");
|
||||
|
||||
this.ended = true;
|
||||
|
||||
lock(this.syncRoot) {
|
||||
if(this.doneEvent != null)
|
||||
this.doneEvent.Set();
|
||||
}
|
||||
// Doesn't need a lock. If another thread wins the race and creates the event
|
||||
// after we just saw it being null, it would be created in an already set
|
||||
// state due to the ended flag (see above) being set to true beforehand!
|
||||
if(this.doneEvent != null)
|
||||
this.doneEvent.Set();
|
||||
|
||||
// Finally, fire the AsyncEnded event
|
||||
EventHandler copy = AsyncEnded;
|
||||
if(copy != null)
|
||||
copy(this, EventArgs.Empty);
|
||||
|
||||
}
|
||||
|
||||
/// <summary>Used to synchronize multithreaded accesses to this object</summary>
|
||||
|
|
215
Source/Tracking/SetProgression.Test.cs
Normal file
215
Source/Tracking/SetProgression.Test.cs
Normal file
|
@ -0,0 +1,215 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
#if UNITTEST
|
||||
|
||||
using NUnit.Framework;
|
||||
using NMock2;
|
||||
|
||||
namespace Nuclex.Support.Tracking {
|
||||
|
||||
/// <summary>Unit Test for the progression set class</summary>
|
||||
[TestFixture]
|
||||
public class SetProgressionTest {
|
||||
|
||||
#region interface ISetProgressionSubscriber
|
||||
|
||||
/// <summary>Interface used to test the set progression.</summary>
|
||||
public interface ISetProgressionSubscriber {
|
||||
|
||||
/// <summary>Called when the set progression's progress changes</summary>
|
||||
/// <param name="sender">Set progression whose progress has changed</param>
|
||||
/// <param name="e">Contains the new progress achieved</param>
|
||||
void ProgressUpdated(object sender, ProgressUpdateEventArgs e);
|
||||
|
||||
/// <summary>Called when the set progression has ended</summary>
|
||||
/// <param name="sender">Set progression that as ended</param>
|
||||
/// <param name="e">Not used</param>
|
||||
void Ended(object sender, EventArgs e);
|
||||
|
||||
}
|
||||
|
||||
#endregion // interface ISetProgressionSubscriber
|
||||
|
||||
#region class ProgressUpdateEventArgsMatcher
|
||||
|
||||
/// <summary>Compares two ProgressUpdateEventArgsInstances for NMock validation</summary>
|
||||
private class ProgressUpdateEventArgsMatcher : Matcher {
|
||||
|
||||
/// <summary>Initializes a new ProgressUpdateEventArgsMatcher </summary>
|
||||
/// <param name="expected">Expected progress update event arguments</param>
|
||||
public ProgressUpdateEventArgsMatcher(ProgressUpdateEventArgs expected) {
|
||||
this.expected = expected;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called by NMock to verfiy the ProgressUpdateEventArgs match the expected value
|
||||
/// </summary>
|
||||
/// <param name="actualAsObject">Actual value to compare to the expected value</param>
|
||||
/// <returns>
|
||||
/// True if the actual value matches the expected value; otherwise false
|
||||
/// </returns>
|
||||
public override bool Matches(object actualAsObject) {
|
||||
ProgressUpdateEventArgs actual = (actualAsObject as ProgressUpdateEventArgs);
|
||||
if(actual == null)
|
||||
return false;
|
||||
|
||||
return (actual.Progress == this.expected.Progress);
|
||||
}
|
||||
|
||||
/// <summary>Creates a string representation of the expected value</summary>
|
||||
/// <param name="writer">Writer to write the string representation into</param>
|
||||
public override void DescribeTo(TextWriter writer) {
|
||||
writer.Write(this.expected.Progress.ToString());
|
||||
}
|
||||
|
||||
/// <summary>Expected progress update event args value</summary>
|
||||
private ProgressUpdateEventArgs expected;
|
||||
|
||||
}
|
||||
|
||||
#endregion // class ProgressUpdateEventArgsMatcher
|
||||
|
||||
#region class TestProgression
|
||||
|
||||
/// <summary>Progression used for testing in this unit test</summary>
|
||||
private class TestProgression : Progression {
|
||||
|
||||
/// <summary>Changes the testing progression's indicated progress</summary>
|
||||
/// <param name="progress">
|
||||
/// New progress to be reported by the testing progression
|
||||
/// </param>
|
||||
public void ChangeProgress(float progress) {
|
||||
OnAsyncProgressUpdated(progress);
|
||||
}
|
||||
|
||||
/// <summary>Transitions the progression into the ended state</summary>
|
||||
public void End() {
|
||||
OnAsyncEnded();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endregion // class TestProgression
|
||||
|
||||
/// <summary>Initialization routine executed before each test is run</summary>
|
||||
[SetUp]
|
||||
public void Setup() {
|
||||
this.mockery = new Mockery();
|
||||
}
|
||||
|
||||
/// <summary>Validates that the set progression properly sums the progress</summary>
|
||||
[Test]
|
||||
public void TestSummedProgress() {
|
||||
SetProgression<TestProgression> testSetProgression =
|
||||
new SetProgression<TestProgression>(
|
||||
new TestProgression[] {
|
||||
new TestProgression(), new TestProgression()
|
||||
}
|
||||
);
|
||||
|
||||
ISetProgressionSubscriber mockedSubscriber = mockSubscriber(testSetProgression);
|
||||
|
||||
Expect.Once.On(mockedSubscriber).
|
||||
Method("ProgressUpdated").
|
||||
With(
|
||||
new Matcher[] {
|
||||
new NMock2.Matchers.TypeMatcher(typeof(SetProgression<TestProgression>)),
|
||||
new ProgressUpdateEventArgsMatcher(new ProgressUpdateEventArgs(0.25f))
|
||||
}
|
||||
);
|
||||
|
||||
testSetProgression.Childs[0].Progression.ChangeProgress(0.5f);
|
||||
|
||||
this.mockery.VerifyAllExpectationsHaveBeenMet();
|
||||
}
|
||||
|
||||
/// <summary>Validates that the set progression respects the weights</summary>
|
||||
[Test]
|
||||
public void TestWeightedSummedProgress() {
|
||||
SetProgression<TestProgression> testSetProgression =
|
||||
new SetProgression<TestProgression>(
|
||||
new WeightedProgression<TestProgression>[] {
|
||||
new WeightedProgression<TestProgression>(new TestProgression(), 1.0f),
|
||||
new WeightedProgression<TestProgression>(new TestProgression(), 2.0f)
|
||||
}
|
||||
);
|
||||
|
||||
ISetProgressionSubscriber mockedSubscriber = mockSubscriber(testSetProgression);
|
||||
|
||||
Expect.Once.On(mockedSubscriber).
|
||||
Method("ProgressUpdated").
|
||||
With(
|
||||
new Matcher[] {
|
||||
new NMock2.Matchers.TypeMatcher(typeof(SetProgression<TestProgression>)),
|
||||
new ProgressUpdateEventArgsMatcher(new ProgressUpdateEventArgs(0.5f / 3.0f))
|
||||
}
|
||||
);
|
||||
|
||||
testSetProgression.Childs[0].Progression.ChangeProgress(0.5f);
|
||||
|
||||
Expect.Once.On(mockedSubscriber).
|
||||
Method("ProgressUpdated").
|
||||
With(
|
||||
new Matcher[] {
|
||||
new NMock2.Matchers.TypeMatcher(typeof(SetProgression<TestProgression>)),
|
||||
new ProgressUpdateEventArgsMatcher(new ProgressUpdateEventArgs(0.5f))
|
||||
}
|
||||
);
|
||||
|
||||
testSetProgression.Childs[1].Progression.ChangeProgress(0.5f);
|
||||
|
||||
this.mockery.VerifyAllExpectationsHaveBeenMet();
|
||||
}
|
||||
|
||||
/// <summary>Mocks a subscriber for the events of a progression</summary>
|
||||
/// <param name="progression">Progression to mock an event subscriber for</param>
|
||||
/// <returns>The mocked event subscriber</returns>
|
||||
private ISetProgressionSubscriber mockSubscriber(Progression progression) {
|
||||
ISetProgressionSubscriber mockedSubscriber =
|
||||
this.mockery.NewMock<ISetProgressionSubscriber>();
|
||||
|
||||
progression.AsyncEnded += new EventHandler(mockedSubscriber.Ended);
|
||||
progression.AsyncProgressUpdated +=
|
||||
new EventHandler<ProgressUpdateEventArgs>(mockedSubscriber.ProgressUpdated);
|
||||
|
||||
return mockedSubscriber;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Validates that the ended event is triggered when the last progression ends
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void TestEndedEvent() {
|
||||
SetProgression<TestProgression> testSetProgression =
|
||||
new SetProgression<TestProgression>(
|
||||
new TestProgression[] {
|
||||
new TestProgression(), new TestProgression()
|
||||
}
|
||||
);
|
||||
|
||||
ISetProgressionSubscriber mockedSubscriber = mockSubscriber(testSetProgression);
|
||||
|
||||
Expect.Exactly(2).On(mockedSubscriber).
|
||||
Method("ProgressUpdated").
|
||||
WithAnyArguments();
|
||||
|
||||
Expect.Once.On(mockedSubscriber).
|
||||
Method("Ended").
|
||||
WithAnyArguments();
|
||||
|
||||
testSetProgression.Childs[0].Progression.End();
|
||||
testSetProgression.Childs[1].Progression.End();
|
||||
|
||||
this.mockery.VerifyAllExpectationsHaveBeenMet();
|
||||
}
|
||||
|
||||
/// <summary>Mock object factory</summary>
|
||||
private Mockery mockery;
|
||||
|
||||
}
|
||||
|
||||
} // namespace Nuclex.Support.Tracking
|
||||
|
||||
#endif // UNITTEST
|
|
@ -11,31 +11,139 @@ namespace Nuclex.Support.Tracking {
|
|||
public class SetProgression<ProgressionType> : Progression
|
||||
where ProgressionType : Progression {
|
||||
|
||||
/// <summary>Performs common initialization for the public constructors</summary>
|
||||
private SetProgression() {
|
||||
this.childs = new List<ObservedProgression<ProgressionType>>();
|
||||
this.asyncProgressUpdatedDelegate =
|
||||
new ObservedProgression<ProgressionType>.ReportDelegate(asyncProgressUpdated);
|
||||
this.asyncEndedDelegate =
|
||||
new ObservedProgression<ProgressionType>.ReportDelegate(asyncEnded);
|
||||
}
|
||||
|
||||
/// <summary>Initializes a new set progression</summary>
|
||||
/// <param name="progressions">Progressions to track with this set</param>
|
||||
/// <param name="childs">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 SetProgression(IEnumerable<ProgressionType> childs)
|
||||
: this() {
|
||||
|
||||
// Construct a WeightedProgression with the default weight for each
|
||||
// progression and wrap it in an ObservedProgression
|
||||
foreach(ProgressionType progression in childs) {
|
||||
this.childs.Add(
|
||||
new ObservedProgression<ProgressionType>(
|
||||
new WeightedProgression<ProgressionType>(progression),
|
||||
this.asyncProgressUpdatedDelegate, this.asyncEndedDelegate
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
// Since all progressions have a weight of 1.0, the total weight is
|
||||
// equal to the number of progressions in our list
|
||||
this.totalWeight = (float)this.childs.Count;
|
||||
|
||||
}
|
||||
|
||||
/// <summary>Initializes a new set progression</summary>
|
||||
/// <param name="progressions">Progressions to track with this set</param>
|
||||
public SetProgression(IEnumerable<WeightedProgression<ProgressionType>> progressions) {
|
||||
/// <param name="childs">Progressions to track with this set</param>
|
||||
public SetProgression(
|
||||
IEnumerable<WeightedProgression<ProgressionType>> childs
|
||||
)
|
||||
: this() {
|
||||
|
||||
// Construct an ObservedProgression around each of the WeightedProgressions
|
||||
float totalWeight = 0.0f;
|
||||
foreach(WeightedProgression<ProgressionType> progression in childs) {
|
||||
this.childs.Add(
|
||||
new ObservedProgression<ProgressionType>(
|
||||
progression,
|
||||
this.asyncProgressUpdatedDelegate, this.asyncEndedDelegate
|
||||
)
|
||||
);
|
||||
|
||||
// Sum up the total weight
|
||||
totalWeight += progression.Weight;
|
||||
}
|
||||
|
||||
// Take over the summed weight of all progressions we were given
|
||||
this.totalWeight = totalWeight;
|
||||
|
||||
}
|
||||
|
||||
/// <summary>Childs contained in the progression set</summary>
|
||||
public ReadOnlyCollection<WeightedProgression<ProgressionType>> Childs {
|
||||
get { return null; }
|
||||
public IList<WeightedProgression<ProgressionType>> Childs {
|
||||
get {
|
||||
|
||||
// The wrapper is constructed only when needed. Most of the time, users will
|
||||
// just create a SetProgression and monitor its progress without ever using
|
||||
// the Childs collection.
|
||||
if(this.wrapper == null) {
|
||||
|
||||
// This doesn't need a lock because it's only a stateless wrapper. If it
|
||||
// is constructed twice, then so be it.
|
||||
this.wrapper = new WeightedProgressionWrapperCollection<ProgressionType>(
|
||||
this.childs
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
return this.wrapper;
|
||||
|
||||
}
|
||||
}
|
||||
/*
|
||||
|
||||
/// <summary>
|
||||
/// Called when the progress of one of the observed progressions changes
|
||||
/// </summary>
|
||||
private void asyncProgressUpdated() {
|
||||
|
||||
// Calculate the sum of the progress reported by our child progressions,
|
||||
// scaled to the weight each progression has assigned to it.
|
||||
float totalProgress = 0.0f;
|
||||
for(int index = 0; index < this.childs.Count; ++index) {
|
||||
totalProgress +=
|
||||
this.childs[index].Progress * this.childs[index].WeightedProgression.Weight;
|
||||
}
|
||||
|
||||
// Calculate the actual combined progress
|
||||
if(this.totalWeight > 0.0f)
|
||||
totalProgress /= this.totalWeight;
|
||||
|
||||
// Send out the progress update
|
||||
OnAsyncProgressUpdated(totalProgress);
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called when an observed progressions ends
|
||||
/// </summary>
|
||||
private void asyncEnded() {
|
||||
|
||||
for(int index = 0; index < this.childs.Count; ++index)
|
||||
if(!this.childs[index].WeightedProgression.Progression.Ended)
|
||||
return;
|
||||
|
||||
OnAsyncEnded();
|
||||
|
||||
}
|
||||
|
||||
/// <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;
|
||||
*/
|
||||
private List<ObservedProgression<ProgressionType>> childs;
|
||||
/// <summary>
|
||||
/// Wrapper collection for exposing the child progressions under the
|
||||
/// WeightedProgression interface
|
||||
/// </summary>
|
||||
private volatile WeightedProgressionWrapperCollection<ProgressionType> wrapper;
|
||||
/// <summary>Summed weight of all progression in the set</summary>
|
||||
private float totalWeight;
|
||||
|
||||
/// <summary>Delegate for the asyncProgressUpdated() method</summary>
|
||||
private ObservedProgression<ProgressionType>.ReportDelegate asyncProgressUpdatedDelegate;
|
||||
/// <summary>Delegate for the asyncEnded() method</summary>
|
||||
private ObservedProgression<ProgressionType>.ReportDelegate asyncEndedDelegate;
|
||||
|
||||
|
||||
}
|
||||
|
||||
} // namespace Nuclex.Support.Tracking
|
||||
|
|
Loading…
Reference in New Issue
Block a user