Renamed ProgressUpdated event to ProgressChanged in order to conform with the status report naming convention; removed progress reporting from the Progression class; moved progress reporting into its own interface which is now optional to implement for any background task; renamed Progression to Waitable since it no longer has anything to do with progress; fixed unit tests

git-svn-id: file:///srv/devel/repo-conversion/nusu@64 d2e56fa2-650e-0410-a79f-9358c0239efd
This commit is contained in:
Markus Ewald 2008-03-26 21:03:49 +00:00
parent 1161ef8f25
commit 7dbfc3c422
15 changed files with 321 additions and 160 deletions

View File

@ -147,9 +147,10 @@
<Compile Include="Source\Tracking\IdleStateEventArgs.cs" /> <Compile Include="Source\Tracking\IdleStateEventArgs.cs" />
<Compile Include="Source\Tracking\Internal\ObservedWeightedProgression.cs" /> <Compile Include="Source\Tracking\Internal\ObservedWeightedProgression.cs" />
<Compile Include="Source\Tracking\Internal\WeightedProgressionWrapperCollection.cs" /> <Compile Include="Source\Tracking\Internal\WeightedProgressionWrapperCollection.cs" />
<Compile Include="Source\Tracking\IProgressReporter.cs" />
<Compile Include="Source\Tracking\IStatusReporter.cs" /> <Compile Include="Source\Tracking\IStatusReporter.cs" />
<Compile Include="Source\Tracking\Request.cs" /> <Compile Include="Source\Tracking\Request.cs" />
<Compile Include="Source\Tracking\Progression.cs" /> <Compile Include="Source\Tracking\Waitable.cs" />
<Compile Include="Source\Tracking\ProgressionTracker.cs" /> <Compile Include="Source\Tracking\ProgressionTracker.cs" />
<Compile Include="Source\Tracking\ProgressionTracker.Test.cs"> <Compile Include="Source\Tracking\ProgressionTracker.Test.cs">
<DependentUpon>ProgressionTracker.cs</DependentUpon> <DependentUpon>ProgressionTracker.cs</DependentUpon>

View File

@ -43,7 +43,7 @@ namespace Nuclex.Support.Scheduling {
/// <summary>Called when the queue operations's progress changes</summary> /// <summary>Called when the queue operations's progress changes</summary>
/// <param name="sender">Queue operation whose progress has changed</param> /// <param name="sender">Queue operation whose progress has changed</param>
/// <param name="e">Contains the new progress achieved</param> /// <param name="e">Contains the new progress achieved</param>
void ProgressUpdated(object sender, ProgressUpdateEventArgs e); void ProgressChanged(object sender, ProgressReportEventArgs e);
/// <summary>Called when the queue operation has ended</summary> /// <summary>Called when the queue operation has ended</summary>
/// <param name="sender">Queue operation that as ended</param> /// <param name="sender">Queue operation that as ended</param>
@ -61,7 +61,7 @@ namespace Nuclex.Support.Scheduling {
/// <summary>Initializes a new ProgressUpdateEventArgsMatcher </summary> /// <summary>Initializes a new ProgressUpdateEventArgsMatcher </summary>
/// <param name="expected">Expected progress update event arguments</param> /// <param name="expected">Expected progress update event arguments</param>
public ProgressUpdateEventArgsMatcher(ProgressUpdateEventArgs expected) { public ProgressUpdateEventArgsMatcher(ProgressReportEventArgs expected) {
this.expected = expected; this.expected = expected;
} }
@ -73,7 +73,7 @@ namespace Nuclex.Support.Scheduling {
/// True if the actual value matches the expected value; otherwise false /// True if the actual value matches the expected value; otherwise false
/// </returns> /// </returns>
public override bool Matches(object actualAsObject) { public override bool Matches(object actualAsObject) {
ProgressUpdateEventArgs actual = (actualAsObject as ProgressUpdateEventArgs); ProgressReportEventArgs actual = (actualAsObject as ProgressReportEventArgs);
if(actual == null) if(actual == null)
return false; return false;
@ -87,7 +87,7 @@ namespace Nuclex.Support.Scheduling {
} }
/// <summary>Expected progress update event args value</summary> /// <summary>Expected progress update event args value</summary>
private ProgressUpdateEventArgs expected; private ProgressReportEventArgs expected;
} }
@ -96,7 +96,10 @@ namespace Nuclex.Support.Scheduling {
#region class TestOperation #region class TestOperation
/// <summary>Progression used for testing in this unit test</summary> /// <summary>Progression used for testing in this unit test</summary>
private class TestOperation : Operation { private class TestOperation : Operation, IProgressReporter {
/// <summary>will be triggered to report when progress has been achieved</summary>
public event EventHandler<ProgressReportEventArgs> AsyncProgressChanged;
/// <summary>Begins executing the operation. Yeah, sure :)</summary> /// <summary>Begins executing the operation. Yeah, sure :)</summary>
public override void Start() { } public override void Start() { }
@ -118,7 +121,7 @@ namespace Nuclex.Support.Scheduling {
/// New progress to be reported by the testing progression /// New progress to be reported by the testing progression
/// </param> /// </param>
public void ChangeProgress(float progress) { public void ChangeProgress(float progress) {
OnAsyncProgressUpdated(progress); OnAsyncProgressChanged(progress);
} }
/// <summary> /// <summary>
@ -130,6 +133,29 @@ namespace Nuclex.Support.Scheduling {
throw this.exception; throw this.exception;
} }
/// <summary>Fires the progress update event</summary>
/// <param name="progress">Progress to report (ranging from 0.0 to 1.0)</param>
/// <remarks>
/// Informs the observers of this progression about the achieved progress.
/// </remarks>
protected virtual void OnAsyncProgressChanged(float progress) {
OnAsyncProgressChanged(new ProgressReportEventArgs(progress));
}
/// <summary>Fires the progress update event</summary>
/// <param name="eventArguments">Progress to report (ranging from 0.0 to 1.0)</param>
/// <remarks>
/// Informs the observers of this progression about the achieved progress.
/// Allows for classes derived from the Progression class to easily provide
/// a custom event arguments class that has been derived from the
/// Progression's ProgressUpdateEventArgs class.
/// </remarks>
protected virtual void OnAsyncProgressChanged(ProgressReportEventArgs eventArguments) {
EventHandler<ProgressReportEventArgs> copy = AsyncProgressChanged;
if(copy != null)
copy(this, eventArguments);
}
/// <summary>Exception that has occured in the background process</summary> /// <summary>Exception that has occured in the background process</summary>
private volatile Exception exception; private volatile Exception exception;
@ -159,22 +185,22 @@ namespace Nuclex.Support.Scheduling {
testQueueOperation.Start(); testQueueOperation.Start();
Expect.Once.On(mockedSubscriber). Expect.Once.On(mockedSubscriber).
Method("ProgressUpdated"). Method("ProgressChanged").
With( With(
new Matcher[] { new Matcher[] {
new NMock2.Matchers.TypeMatcher(typeof(QueueOperation<TestOperation>)), new NMock2.Matchers.TypeMatcher(typeof(QueueOperation<TestOperation>)),
new ProgressUpdateEventArgsMatcher(new ProgressUpdateEventArgs(0.25f)) new ProgressUpdateEventArgsMatcher(new ProgressReportEventArgs(0.25f))
} }
); );
operation1.ChangeProgress(0.5f); operation1.ChangeProgress(0.5f);
Expect.Once.On(mockedSubscriber). Expect.Once.On(mockedSubscriber).
Method("ProgressUpdated"). Method("ProgressChanged").
With( With(
new Matcher[] { new Matcher[] {
new NMock2.Matchers.TypeMatcher(typeof(QueueOperation<TestOperation>)), new NMock2.Matchers.TypeMatcher(typeof(QueueOperation<TestOperation>)),
new ProgressUpdateEventArgsMatcher(new ProgressUpdateEventArgs(0.5f)) new ProgressUpdateEventArgsMatcher(new ProgressReportEventArgs(0.5f))
} }
); );
@ -191,8 +217,8 @@ namespace Nuclex.Support.Scheduling {
this.mockery.NewMock<IQueueOperationSubscriber>(); this.mockery.NewMock<IQueueOperationSubscriber>();
operation.AsyncEnded += new EventHandler(mockedSubscriber.Ended); operation.AsyncEnded += new EventHandler(mockedSubscriber.Ended);
operation.AsyncProgressUpdated += (operation as IProgressReporter).AsyncProgressChanged +=
new EventHandler<ProgressUpdateEventArgs>(mockedSubscriber.ProgressUpdated); new EventHandler<ProgressReportEventArgs>(mockedSubscriber.ProgressChanged);
return mockedSubscriber; return mockedSubscriber;
} }

View File

@ -32,15 +32,8 @@ namespace Nuclex.Support.Scheduling {
public class QueueOperation<OperationType> : Operation public class QueueOperation<OperationType> : Operation
where OperationType : Operation { where OperationType : Operation {
/// <summary>Initializes a new queue operation</summary> /// <summary>will be triggered to report when progress has been achieved</summary>
private QueueOperation() { public event EventHandler<ProgressReportEventArgs> AsyncProgressUpdated;
this.asyncOperationEndedDelegate = new EventHandler(asyncOperationEnded);
this.asyncOperationProgressUpdatedDelegate = new EventHandler<ProgressUpdateEventArgs>(
asyncOperationProgressUpdated
);
this.children = new List<WeightedProgression<OperationType>>();
}
/// <summary>Initializes a new queue operation with default weights</summary> /// <summary>Initializes a new queue operation with default weights</summary>
/// <param name="childs">Child operations to execute in this operation</param> /// <param name="childs">Child operations to execute in this operation</param>
@ -74,6 +67,16 @@ namespace Nuclex.Support.Scheduling {
} }
/// <summary>Initializes a new queue operation</summary>
private QueueOperation() {
this.asyncOperationEndedDelegate = new EventHandler(asyncOperationEnded);
this.asyncOperationProgressChangedDelegate = new EventHandler<ProgressReportEventArgs>(
asyncOperationProgressChanged
);
this.children = new List<WeightedProgression<OperationType>>();
}
/// <summary>Provides access to the child operations of this queue</summary> /// <summary>Provides access to the child operations of this queue</summary>
public IList<WeightedProgression<OperationType>> Children { public IList<WeightedProgression<OperationType>> Children {
get { return this.children; } get { return this.children; }
@ -93,6 +96,29 @@ namespace Nuclex.Support.Scheduling {
throw this.exception; throw this.exception;
} }
/// <summary>Fires the progress update event</summary>
/// <param name="progress">Progress to report (ranging from 0.0 to 1.0)</param>
/// <remarks>
/// Informs the observers of this progression about the achieved progress.
/// </remarks>
protected virtual void OnAsyncProgressChanged(float progress) {
OnAsyncProgressChanged(new ProgressReportEventArgs(progress));
}
/// <summary>Fires the progress update event</summary>
/// <param name="eventArguments">Progress to report (ranging from 0.0 to 1.0)</param>
/// <remarks>
/// Informs the observers of this progression about the achieved progress.
/// Allows for classes derived from the Progression class to easily provide
/// a custom event arguments class that has been derived from the
/// Progression's ProgressUpdateEventArgs class.
/// </remarks>
protected virtual void OnAsyncProgressChanged(ProgressReportEventArgs eventArguments) {
EventHandler<ProgressReportEventArgs> copy = AsyncProgressUpdated;
if(copy != null)
copy(this, eventArguments);
}
/// <summary>Prepares the current operation and calls its Begin() method</summary> /// <summary>Prepares the current operation and calls its Begin() method</summary>
/// <remarks> /// <remarks>
/// This subscribes the queue to the events of to the current operation /// This subscribes the queue to the events of to the current operation
@ -102,7 +128,10 @@ namespace Nuclex.Support.Scheduling {
OperationType operation = this.children[this.currentOperationIndex].Progression; OperationType operation = this.children[this.currentOperationIndex].Progression;
operation.AsyncEnded += this.asyncOperationEndedDelegate; operation.AsyncEnded += this.asyncOperationEndedDelegate;
operation.AsyncProgressUpdated += this.asyncOperationProgressUpdatedDelegate;
IProgressReporter progressReporter = operation as IProgressReporter;
if(progressReporter != null)
progressReporter.AsyncProgressChanged += this.asyncOperationProgressChangedDelegate;
operation.Start(); operation.Start();
} }
@ -118,7 +147,10 @@ namespace Nuclex.Support.Scheduling {
// Disconnect from the operation's events // Disconnect from the operation's events
operation.AsyncEnded -= this.asyncOperationEndedDelegate; operation.AsyncEnded -= this.asyncOperationEndedDelegate;
operation.AsyncProgressUpdated -= this.asyncOperationProgressUpdatedDelegate;
IProgressReporter progressReporter = operation as IProgressReporter;
if(progressReporter != null)
progressReporter.AsyncProgressChanged -= this.asyncOperationProgressChangedDelegate;
try { try {
operation.Join(); operation.Join();
@ -127,7 +159,7 @@ namespace Nuclex.Support.Scheduling {
this.completedWeight += this.children[this.currentOperationIndex].Weight; this.completedWeight += this.children[this.currentOperationIndex].Weight;
// Trigger another progress update // Trigger another progress update
OnAsyncProgressUpdated(this.completedWeight / this.totalWeight); OnAsyncProgressChanged(this.completedWeight / this.totalWeight);
} }
catch(Exception exception) { catch(Exception exception) {
this.exception = exception; this.exception = exception;
@ -165,7 +197,7 @@ namespace Nuclex.Support.Scheduling {
/// <summary>Called when currently executing operation makes progress</summary> /// <summary>Called when currently executing operation makes progress</summary>
/// <param name="sender">Operation that has achieved progress</param> /// <param name="sender">Operation that has achieved progress</param>
/// <param name="e">Not used</param> /// <param name="e">Not used</param>
private void asyncOperationProgressUpdated(object sender, ProgressUpdateEventArgs e) { private void asyncOperationProgressChanged(object sender, ProgressReportEventArgs e) {
// Determine the completed weight of the currently executing operation // Determine the completed weight of the currently executing operation
float currentOperationCompletedWeight = float currentOperationCompletedWeight =
@ -176,14 +208,14 @@ namespace Nuclex.Support.Scheduling {
(this.completedWeight + currentOperationCompletedWeight) / this.totalWeight; (this.completedWeight + currentOperationCompletedWeight) / this.totalWeight;
// Done, we can send the actual progress to any event subscribers // Done, we can send the actual progress to any event subscribers
OnAsyncProgressUpdated(progress); OnAsyncProgressChanged(progress);
} }
/// <summary>Delegate to the asyncOperationEnded() method</summary> /// <summary>Delegate to the asyncOperationEnded() method</summary>
private EventHandler asyncOperationEndedDelegate; private EventHandler asyncOperationEndedDelegate;
/// <summary>Delegate to the asyncOperationProgressUpdated() method</summary> /// <summary>Delegate to the asyncOperationProgressUpdated() method</summary>
private EventHandler<ProgressUpdateEventArgs> asyncOperationProgressUpdatedDelegate; private EventHandler<ProgressReportEventArgs> asyncOperationProgressChangedDelegate;
/// <summary>Operations being managed in the queue</summary> /// <summary>Operations being managed in the queue</summary>
private List<WeightedProgression<OperationType>> children; private List<WeightedProgression<OperationType>> children;
/// <summary>Summed weight of all operations in the queue</summary> /// <summary>Summed weight of all operations in the queue</summary>

View File

@ -0,0 +1,34 @@
#region CPL License
/*
Nuclex Framework
Copyright (C) 2002-2008 Nuclex Development Labs
This library is free software; you can redistribute it and/or
modify it under the terms of the IBM Common Public License as
published by the IBM Corporation; either version 1.0 of the
License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
IBM Common Public License for more details.
You should have received a copy of the IBM Common Public
License along with this library
*/
#endregion
using System;
using System.Collections.Generic;
namespace Nuclex.Support.Tracking {
/// <summary>Interface for processes that report their progress</summary>
public interface IProgressReporter {
/// <summary>Triggered when the status of the process changes</summary>
event EventHandler<ProgressReportEventArgs> AsyncProgressChanged;
}
} // namespace Nuclex.Support.Tracking

View File

@ -27,7 +27,7 @@ namespace Nuclex.Support.Tracking {
public interface IStatusReporter { public interface IStatusReporter {
/// <summary>Triggered when the status of the process changes</summary> /// <summary>Triggered when the status of the process changes</summary>
event EventHandler<StatusReportEventArgs> StatusChanged; event EventHandler<StatusReportEventArgs> AsyncStatusChanged;
} }

View File

@ -28,7 +28,7 @@ namespace Nuclex.Support.Tracking {
/// Type of the progression that is being observed /// Type of the progression that is being observed
/// </typeparam> /// </typeparam>
internal class ObservedWeightedProgression<ProgressionType> : IDisposable internal class ObservedWeightedProgression<ProgressionType> : IDisposable
where ProgressionType : Progression { where ProgressionType : Waitable {
/// <summary>Delegate for reporting progress updates</summary> /// <summary>Delegate for reporting progress updates</summary>
public delegate void ReportDelegate(); public delegate void ReportDelegate();
@ -69,8 +69,16 @@ namespace Nuclex.Support.Tracking {
if(weightedProgression.Progression.Ended) { if(weightedProgression.Progression.Ended) {
this.progress = 1.0f; this.progress = 1.0f;
} else { } else {
this.weightedProgression.Progression.AsyncProgressUpdated += this.progressReporter = this.weightedProgression.Progression as IProgressReporter;
new EventHandler<ProgressUpdateEventArgs>(asyncProgressUpdated);
if(this.progressReporter != null) {
this.asyncProgressChangedEventHandler = new EventHandler<ProgressReportEventArgs>(
asyncProgressChanged
);
this.progressReporter.AsyncProgressChanged +=
this.asyncProgressChangedEventHandler;
}
} }
} }
@ -119,7 +127,7 @@ namespace Nuclex.Support.Tracking {
/// <summary>Called when the progress of the observed progression changes</summary> /// <summary>Called when the progress of the observed progression changes</summary>
/// <param name="sender">Progression whose progress has changed</param> /// <param name="sender">Progression whose progress has changed</param>
/// <param name="e">Contains the updated progress</param> /// <param name="e">Contains the updated progress</param>
private void asyncProgressUpdated(object sender, ProgressUpdateEventArgs e) { private void asyncProgressChanged(object sender, ProgressReportEventArgs e) {
this.progress = e.Progress; this.progress = e.Progress;
this.progressUpdateCallback(); this.progressUpdateCallback();
} }
@ -138,8 +146,12 @@ namespace Nuclex.Support.Tracking {
this.weightedProgression.Progression.AsyncEnded -= this.weightedProgression.Progression.AsyncEnded -=
new EventHandler(asyncEnded); new EventHandler(asyncEnded);
this.weightedProgression.Progression.AsyncProgressUpdated -= if(this.progressReporter != null) {
new EventHandler<ProgressUpdateEventArgs>(asyncProgressUpdated); this.progressReporter.AsyncProgressChanged -=
this.asyncProgressChangedEventHandler;
this.asyncProgressChangedEventHandler = null;
}
this.endedCallback = null; this.endedCallback = null;
this.progressUpdateCallback = null; this.progressUpdateCallback = null;
@ -150,6 +162,9 @@ namespace Nuclex.Support.Tracking {
} }
private EventHandler<ProgressReportEventArgs> asyncProgressChangedEventHandler;
/// <summary>The observed progression's progress reporting interface</summary>
private IProgressReporter progressReporter;
/// <summary>The weighted progression that is being observed</summary> /// <summary>The weighted progression that is being observed</summary>
private WeightedProgression<ProgressionType> weightedProgression; private WeightedProgression<ProgressionType> weightedProgression;
/// <summary>Callback to invoke when the progress updates</summary> /// <summary>Callback to invoke when the progress updates</summary>

View File

@ -51,7 +51,7 @@ namespace Nuclex.Support.Tracking {
TransformingReadOnlyCollection< TransformingReadOnlyCollection<
ObservedWeightedProgression<ProgressionType>, WeightedProgression<ProgressionType> ObservedWeightedProgression<ProgressionType>, WeightedProgression<ProgressionType>
> >
where ProgressionType : Progression { where ProgressionType : Waitable {
/// <summary>Initializes a new weighted progression collection wrapper</summary> /// <summary>Initializes a new weighted progression collection wrapper</summary>
/// <param name="items">Items to be exposed as weighted progressions</param> /// <param name="items">Items to be exposed as weighted progressions</param>

View File

@ -24,11 +24,11 @@ using System.Collections.Generic;
namespace Nuclex.Support.Tracking { namespace Nuclex.Support.Tracking {
/// <summary>Event arguments for a progress update notification</summary> /// <summary>Event arguments for a progress update notification</summary>
public class ProgressUpdateEventArgs : EventArgs { public class ProgressReportEventArgs : EventArgs {
/// <summary>Initializes the progress update informations</summary> /// <summary>Initializes the progress update informations</summary>
/// <param name="progress">Achieved progress ranging from 0.0 to 1.0</param> /// <param name="progress">Achieved progress ranging from 0.0 to 1.0</param>
public ProgressUpdateEventArgs(float progress) { public ProgressReportEventArgs(float progress) {
this.progress = progress; this.progress = progress;
} }

View File

@ -41,7 +41,7 @@ namespace Nuclex.Support.Tracking {
/// <summary>Called when the progression tracker's progress changes</summary> /// <summary>Called when the progression tracker's progress changes</summary>
/// <param name="sender">Progression tracker whose progress has changed</param> /// <param name="sender">Progression tracker whose progress has changed</param>
/// <param name="e">Contains the new progress achieved</param> /// <param name="e">Contains the new progress achieved</param>
void ProgressUpdated(object sender, ProgressUpdateEventArgs e); void ProgressUpdated(object sender, ProgressReportEventArgs e);
/// <summary>Called when the progression tracker's idle state changes</summary> /// <summary>Called when the progression tracker's idle state changes</summary>
/// <param name="sender">Progression tracker whose idle state has changed</param> /// <param name="sender">Progression tracker whose idle state has changed</param>
@ -59,7 +59,7 @@ namespace Nuclex.Support.Tracking {
/// <summary>Initializes a new ProgressUpdateEventArgsMatcher </summary> /// <summary>Initializes a new ProgressUpdateEventArgsMatcher </summary>
/// <param name="expected">Expected progress update event arguments</param> /// <param name="expected">Expected progress update event arguments</param>
public ProgressUpdateEventArgsMatcher(ProgressUpdateEventArgs expected) { public ProgressUpdateEventArgsMatcher(ProgressReportEventArgs expected) {
this.expected = expected; this.expected = expected;
} }
@ -71,7 +71,7 @@ namespace Nuclex.Support.Tracking {
/// True if the actual value matches the expected value; otherwise false /// True if the actual value matches the expected value; otherwise false
/// </returns> /// </returns>
public override bool Matches(object actualAsObject) { public override bool Matches(object actualAsObject) {
ProgressUpdateEventArgs actual = (actualAsObject as ProgressUpdateEventArgs); ProgressReportEventArgs actual = (actualAsObject as ProgressReportEventArgs);
if(actual == null) if(actual == null)
return false; return false;
@ -85,7 +85,7 @@ namespace Nuclex.Support.Tracking {
} }
/// <summary>Expected progress update event args value</summary> /// <summary>Expected progress update event args value</summary>
private ProgressUpdateEventArgs expected; private ProgressReportEventArgs expected;
} }
@ -94,14 +94,17 @@ namespace Nuclex.Support.Tracking {
#region class TestProgression #region class TestProgression
/// <summary>Progression used for testing in this unit test</summary> /// <summary>Progression used for testing in this unit test</summary>
private class TestProgression : Progression { private class TestProgression : Waitable {
/// <summary>will be triggered to report when progress has been achieved</summary>
public event EventHandler<ProgressReportEventArgs> AsyncProgressChanged;
/// <summary>Changes the testing progression's indicated progress</summary> /// <summary>Changes the testing progression's indicated progress</summary>
/// <param name="progress"> /// <param name="progress">
/// New progress to be reported by the testing progression /// New progress to be reported by the testing progression
/// </param> /// </param>
public void ChangeProgress(float progress) { public void ChangeProgress(float progress) {
OnAsyncProgressUpdated(progress); OnAsyncProgressChanged(progress);
} }
/// <summary>Transitions the progression into the ended state</summary> /// <summary>Transitions the progression into the ended state</summary>
@ -109,6 +112,29 @@ namespace Nuclex.Support.Tracking {
OnAsyncEnded(); OnAsyncEnded();
} }
/// <summary>Fires the progress update event</summary>
/// <param name="progress">Progress to report (ranging from 0.0 to 1.0)</param>
/// <remarks>
/// Informs the observers of this progression about the achieved progress.
/// </remarks>
protected virtual void OnAsyncProgressChanged(float progress) {
OnAsyncProgressChanged(new ProgressReportEventArgs(progress));
}
/// <summary>Fires the progress update event</summary>
/// <param name="eventArguments">Progress to report (ranging from 0.0 to 1.0)</param>
/// <remarks>
/// Informs the observers of this progression about the achieved progress.
/// Allows for classes derived from the Progression class to easily provide
/// a custom event arguments class that has been derived from the
/// Progression's ProgressUpdateEventArgs class.
/// </remarks>
protected virtual void OnAsyncProgressChanged(ProgressReportEventArgs eventArguments) {
EventHandler<ProgressReportEventArgs> copy = AsyncProgressChanged;
if(copy != null)
copy(this, eventArguments);
}
} }
#endregion // class TestProgression #endregion // class TestProgression
@ -135,7 +161,7 @@ namespace Nuclex.Support.Tracking {
With( With(
new Matcher[] { new Matcher[] {
new NMock2.Matchers.TypeMatcher(typeof(ProgressionTracker)), new NMock2.Matchers.TypeMatcher(typeof(ProgressionTracker)),
new ProgressUpdateEventArgsMatcher(new ProgressUpdateEventArgs(0.0f)) new ProgressUpdateEventArgsMatcher(new ProgressReportEventArgs(0.0f))
} }
); );
@ -149,7 +175,7 @@ namespace Nuclex.Support.Tracking {
With( With(
new Matcher[] { new Matcher[] {
new NMock2.Matchers.TypeMatcher(typeof(ProgressionTracker)), new NMock2.Matchers.TypeMatcher(typeof(ProgressionTracker)),
new ProgressUpdateEventArgsMatcher(new ProgressUpdateEventArgs(0.25f)) new ProgressUpdateEventArgsMatcher(new ProgressReportEventArgs(0.25f))
} }
); );
@ -181,7 +207,7 @@ namespace Nuclex.Support.Tracking {
With( With(
new Matcher[] { new Matcher[] {
new NMock2.Matchers.TypeMatcher(typeof(ProgressionTracker)), new NMock2.Matchers.TypeMatcher(typeof(ProgressionTracker)),
new ProgressUpdateEventArgsMatcher(new ProgressUpdateEventArgs(0.0f)) new ProgressUpdateEventArgsMatcher(new ProgressReportEventArgs(0.0f))
} }
); );
@ -195,7 +221,7 @@ namespace Nuclex.Support.Tracking {
With( With(
new Matcher[] { new Matcher[] {
new NMock2.Matchers.TypeMatcher(typeof(ProgressionTracker)), new NMock2.Matchers.TypeMatcher(typeof(ProgressionTracker)),
new ProgressUpdateEventArgsMatcher(new ProgressUpdateEventArgs(0.25f)) new ProgressUpdateEventArgsMatcher(new ProgressReportEventArgs(0.25f))
} }
); );
@ -206,7 +232,7 @@ namespace Nuclex.Support.Tracking {
With( With(
new Matcher[] { new Matcher[] {
new NMock2.Matchers.TypeMatcher(typeof(ProgressionTracker)), new NMock2.Matchers.TypeMatcher(typeof(ProgressionTracker)),
new ProgressUpdateEventArgsMatcher(new ProgressUpdateEventArgs(0.75f)) new ProgressUpdateEventArgsMatcher(new ProgressReportEventArgs(0.75f))
} }
); );
@ -220,7 +246,7 @@ namespace Nuclex.Support.Tracking {
With( With(
new Matcher[] { new Matcher[] {
new NMock2.Matchers.TypeMatcher(typeof(ProgressionTracker)), new NMock2.Matchers.TypeMatcher(typeof(ProgressionTracker)),
new ProgressUpdateEventArgsMatcher(new ProgressUpdateEventArgs(1.0f)) new ProgressUpdateEventArgsMatcher(new ProgressReportEventArgs(1.0f))
} }
); );
@ -243,7 +269,7 @@ namespace Nuclex.Support.Tracking {
IProgressionTrackerSubscriber mockedSubscriber = mockSubscriber(tracker); IProgressionTrackerSubscriber mockedSubscriber = mockSubscriber(tracker);
tracker.Track(Progression.EndedDummy); tracker.Track(Waitable.EndedDummy);
this.mockery.VerifyAllExpectationsHaveBeenMet(); this.mockery.VerifyAllExpectationsHaveBeenMet();
} }
@ -267,7 +293,7 @@ namespace Nuclex.Support.Tracking {
With( With(
new Matcher[] { new Matcher[] {
new NMock2.Matchers.TypeMatcher(typeof(ProgressionTracker)), new NMock2.Matchers.TypeMatcher(typeof(ProgressionTracker)),
new ProgressUpdateEventArgsMatcher(new ProgressUpdateEventArgs(0.0f)) new ProgressUpdateEventArgsMatcher(new ProgressReportEventArgs(0.0f))
} }
); );
@ -279,18 +305,18 @@ namespace Nuclex.Support.Tracking {
With( With(
new Matcher[] { new Matcher[] {
new NMock2.Matchers.TypeMatcher(typeof(ProgressionTracker)), new NMock2.Matchers.TypeMatcher(typeof(ProgressionTracker)),
new ProgressUpdateEventArgsMatcher(new ProgressUpdateEventArgs(0.5f)) new ProgressUpdateEventArgsMatcher(new ProgressReportEventArgs(0.5f))
} }
); );
tracker.Track(Progression.EndedDummy); tracker.Track(Waitable.EndedDummy);
Expect.Once.On(mockedSubscriber). Expect.Once.On(mockedSubscriber).
Method("ProgressUpdated"). Method("ProgressUpdated").
With( With(
new Matcher[] { new Matcher[] {
new NMock2.Matchers.TypeMatcher(typeof(ProgressionTracker)), new NMock2.Matchers.TypeMatcher(typeof(ProgressionTracker)),
new ProgressUpdateEventArgsMatcher(new ProgressUpdateEventArgs(1.0f)) new ProgressUpdateEventArgsMatcher(new ProgressReportEventArgs(1.0f))
} }
); );
@ -316,7 +342,7 @@ namespace Nuclex.Support.Tracking {
tracker.AsyncIdleStateChanged += tracker.AsyncIdleStateChanged +=
(EventHandler<IdleStateEventArgs>)delegate(object sender, IdleStateEventArgs arguments) { (EventHandler<IdleStateEventArgs>)delegate(object sender, IdleStateEventArgs arguments) {
tracker.Track(Progression.EndedDummy); tracker.Track(Waitable.EndedDummy);
}; };
test1.End(); test1.End();
@ -333,7 +359,7 @@ namespace Nuclex.Support.Tracking {
new EventHandler<IdleStateEventArgs>(mockedSubscriber.IdleStateChanged); new EventHandler<IdleStateEventArgs>(mockedSubscriber.IdleStateChanged);
tracker.AsyncProgressUpdated += tracker.AsyncProgressUpdated +=
new EventHandler<ProgressUpdateEventArgs>(mockedSubscriber.ProgressUpdated); new EventHandler<ProgressReportEventArgs>(mockedSubscriber.ProgressUpdated);
return mockedSubscriber; return mockedSubscriber;
} }

View File

@ -50,7 +50,7 @@ namespace Nuclex.Support.Tracking {
/// the specified progression /// the specified progression
/// </summary> /// </summary>
/// <param name="toMatch">Progression to match against</param> /// <param name="toMatch">Progression to match against</param>
public ProgressionMatcher(Progression toMatch) { public ProgressionMatcher(Waitable toMatch) {
this.toMatch = toMatch; this.toMatch = toMatch;
} }
@ -59,12 +59,12 @@ namespace Nuclex.Support.Tracking {
/// progression of the instance /// progression of the instance
/// </summary> /// </summary>
/// <param name="other">Progression to match to the comparison progression</param> /// <param name="other">Progression to match to the comparison progression</param>
public bool Matches(ObservedWeightedProgression<Progression> other) { public bool Matches(ObservedWeightedProgression<Waitable> other) {
return ReferenceEquals(other.WeightedProgression.Progression, this.toMatch); return ReferenceEquals(other.WeightedProgression.Progression, this.toMatch);
} }
/// <summary>Progression this instance compares against</summary> /// <summary>Progression this instance compares against</summary>
private Progression toMatch; private Waitable toMatch;
} }
@ -80,18 +80,18 @@ namespace Nuclex.Support.Tracking {
public event EventHandler<IdleStateEventArgs> AsyncIdleStateChanged; public event EventHandler<IdleStateEventArgs> AsyncIdleStateChanged;
/// <summary>Triggered when the total progress has changed</summary> /// <summary>Triggered when the total progress has changed</summary>
public event EventHandler<ProgressUpdateEventArgs> AsyncProgressUpdated; public event EventHandler<ProgressReportEventArgs> AsyncProgressUpdated;
/// <summary>Initializes a new progression tracker</summary> /// <summary>Initializes a new progression tracker</summary>
public ProgressionTracker() { public ProgressionTracker() {
this.trackedProgressions = new List<ObservedWeightedProgression<Progression>>(); this.trackedProgressions = new List<ObservedWeightedProgression<Waitable>>();
this.idle = true; this.idle = true;
this.asyncEndedDelegate = this.asyncEndedDelegate =
new ObservedWeightedProgression<Progression>.ReportDelegate(asyncEnded); new ObservedWeightedProgression<Waitable>.ReportDelegate(asyncEnded);
this.asyncProgressUpdatedDelegate = this.asyncProgressUpdatedDelegate =
new ObservedWeightedProgression<Progression>.ReportDelegate(asyncProgressUpdated); new ObservedWeightedProgression<Waitable>.ReportDelegate(asyncProgressUpdated);
} }
@ -115,14 +115,14 @@ namespace Nuclex.Support.Tracking {
/// <summary>Begins tracking the specified progression</summary> /// <summary>Begins tracking the specified progression</summary>
/// <param name="progression">Progression to be tracked</param> /// <param name="progression">Progression to be tracked</param>
public void Track(Progression progression) { public void Track(Waitable progression) {
Track(progression, 1.0f); Track(progression, 1.0f);
} }
/// <summary>Begins tracking the specified progression</summary> /// <summary>Begins tracking the specified progression</summary>
/// <param name="progression">Progression to be tracked</param> /// <param name="progression">Progression to be tracked</param>
/// <param name="weight">Weight to assign to this progression</param> /// <param name="weight">Weight to assign to this progression</param>
public void Track(Progression progression, float weight) { public void Track(Waitable progression, float weight) {
// Add the new progression into the tracking list. This has to be done // Add the new progression into the tracking list. This has to be done
// inside a lock to prevent issues with the progressUpdate callback, which could // inside a lock to prevent issues with the progressUpdate callback, which could
@ -150,8 +150,8 @@ namespace Nuclex.Support.Tracking {
// receive them. The lock eliminates the risk of processing a progress update // receive them. The lock eliminates the risk of processing a progress update
// before the progression has been added to the tracked progressions list. // before the progression has been added to the tracked progressions list.
this.trackedProgressions.Add( this.trackedProgressions.Add(
new ObservedWeightedProgression<Progression>( new ObservedWeightedProgression<Waitable>(
new WeightedProgression<Progression>(progression, weight), new WeightedProgression<Waitable>(progression, weight),
this.asyncProgressUpdatedDelegate, this.asyncProgressUpdatedDelegate,
this.asyncEndedDelegate this.asyncEndedDelegate
) )
@ -167,9 +167,9 @@ namespace Nuclex.Support.Tracking {
// Construct a new progression observer and add the progression to our // Construct a new progression observer and add the progression to our
// list of tracked progressions. // list of tracked progressions.
ObservedWeightedProgression<Progression> observedProgression = ObservedWeightedProgression<Waitable> observedProgression =
new ObservedWeightedProgression<Progression>( new ObservedWeightedProgression<Waitable>(
new WeightedProgression<Progression>(progression, weight), new WeightedProgression<Waitable>(progression, weight),
this.asyncProgressUpdatedDelegate, this.asyncProgressUpdatedDelegate,
this.asyncEndedDelegate this.asyncEndedDelegate
); );
@ -202,12 +202,12 @@ namespace Nuclex.Support.Tracking {
/// <summary>Stops tracking the specified progression</summary> /// <summary>Stops tracking the specified progression</summary>
/// <param name="progression">Progression to stop tracking of</param> /// <param name="progression">Progression to stop tracking of</param>
public void Untrack(Progression progression) { public void Untrack(Waitable progression) {
lock(this.trackedProgressions) { lock(this.trackedProgressions) {
// Locate the object to be untracked in our collection // Locate the object to be untracked in our collection
int removeIndex = this.trackedProgressions.FindIndex( int removeIndex = this.trackedProgressions.FindIndex(
new Predicate<ObservedWeightedProgression<Progression>>( new Predicate<ObservedWeightedProgression<Waitable>>(
new ProgressionMatcher(progression).Matches new ProgressionMatcher(progression).Matches
) )
); );
@ -216,7 +216,7 @@ namespace Nuclex.Support.Tracking {
// Remove and dispose the progression the user wants to untrack // Remove and dispose the progression the user wants to untrack
{ {
ObservedWeightedProgression<Progression> wrappedProgression = ObservedWeightedProgression<Waitable> wrappedProgression =
this.trackedProgressions[removeIndex]; this.trackedProgressions[removeIndex];
this.trackedProgressions.RemoveAt(removeIndex); this.trackedProgressions.RemoveAt(removeIndex);
@ -266,9 +266,9 @@ namespace Nuclex.Support.Tracking {
/// <summary>Fires the AsyncProgressUpdated event</summary> /// <summary>Fires the AsyncProgressUpdated event</summary>
/// <param name="progress">New progress to report</param> /// <param name="progress">New progress to report</param>
protected virtual void OnAsyncProgressUpdated(float progress) { protected virtual void OnAsyncProgressUpdated(float progress) {
EventHandler<ProgressUpdateEventArgs> copy = AsyncProgressUpdated; EventHandler<ProgressReportEventArgs> copy = AsyncProgressUpdated;
if(copy != null) if(copy != null)
copy(this, new ProgressUpdateEventArgs(progress)); copy(this, new ProgressReportEventArgs(progress));
} }
/// <summary>Recalculates the total progress of the tracker</summary> /// <summary>Recalculates the total progress of the tracker</summary>
@ -351,11 +351,11 @@ namespace Nuclex.Support.Tracking {
/// <summary>Total weight of all progressions being tracked</summary> /// <summary>Total weight of all progressions being tracked</summary>
private volatile float totalWeight; private volatile float totalWeight;
/// <summary>Progressions being tracked by this tracker</summary> /// <summary>Progressions being tracked by this tracker</summary>
private List<ObservedWeightedProgression<Progression>> trackedProgressions; private List<ObservedWeightedProgression<Waitable>> trackedProgressions;
/// <summary>Delegate for the asyncEnded() method</summary> /// <summary>Delegate for the asyncEnded() method</summary>
private ObservedWeightedProgression<Progression>.ReportDelegate asyncEndedDelegate; private ObservedWeightedProgression<Waitable>.ReportDelegate asyncEndedDelegate;
/// <summary>Delegate for the asyncProgressUpdated() method</summary> /// <summary>Delegate for the asyncProgressUpdated() method</summary>
private ObservedWeightedProgression<Progression>.ReportDelegate asyncProgressUpdatedDelegate; private ObservedWeightedProgression<Waitable>.ReportDelegate asyncProgressUpdatedDelegate;
} }

View File

@ -37,7 +37,7 @@ namespace Nuclex.Support.Tracking {
/// OnAsyncEnded(), no matter what the outcome of your background operation is. /// OnAsyncEnded(), no matter what the outcome of your background operation is.
/// </para> /// </para>
/// </remarks> /// </remarks>
public abstract class Request : Progression { public abstract class Request : Waitable {
#region class EndedDummyRequest #region class EndedDummyRequest

View File

@ -41,7 +41,7 @@ namespace Nuclex.Support.Tracking {
/// <summary>Called when the set progression's progress changes</summary> /// <summary>Called when the set progression's progress changes</summary>
/// <param name="sender">Set progression whose progress has changed</param> /// <param name="sender">Set progression whose progress has changed</param>
/// <param name="e">Contains the new progress achieved</param> /// <param name="e">Contains the new progress achieved</param>
void ProgressUpdated(object sender, ProgressUpdateEventArgs e); void ProgressChanged(object sender, ProgressReportEventArgs e);
/// <summary>Called when the set progression has ended</summary> /// <summary>Called when the set progression has ended</summary>
/// <param name="sender">Set progression that as ended</param> /// <param name="sender">Set progression that as ended</param>
@ -59,7 +59,7 @@ namespace Nuclex.Support.Tracking {
/// <summary>Initializes a new ProgressUpdateEventArgsMatcher </summary> /// <summary>Initializes a new ProgressUpdateEventArgsMatcher </summary>
/// <param name="expected">Expected progress update event arguments</param> /// <param name="expected">Expected progress update event arguments</param>
public ProgressUpdateEventArgsMatcher(ProgressUpdateEventArgs expected) { public ProgressUpdateEventArgsMatcher(ProgressReportEventArgs expected) {
this.expected = expected; this.expected = expected;
} }
@ -71,7 +71,7 @@ namespace Nuclex.Support.Tracking {
/// True if the actual value matches the expected value; otherwise false /// True if the actual value matches the expected value; otherwise false
/// </returns> /// </returns>
public override bool Matches(object actualAsObject) { public override bool Matches(object actualAsObject) {
ProgressUpdateEventArgs actual = (actualAsObject as ProgressUpdateEventArgs); ProgressReportEventArgs actual = (actualAsObject as ProgressReportEventArgs);
if(actual == null) if(actual == null)
return false; return false;
@ -85,23 +85,26 @@ namespace Nuclex.Support.Tracking {
} }
/// <summary>Expected progress update event args value</summary> /// <summary>Expected progress update event args value</summary>
private ProgressUpdateEventArgs expected; private ProgressReportEventArgs expected;
} }
#endregion // class ProgressUpdateEventArgsMatcher #endregion // class ProgressUpdateEventArgsMatcher
#region class TestProgression #region class TestWaitable
/// <summary>Progression used for testing in this unit test</summary> /// <summary>Progression used for testing in this unit test</summary>
private class TestProgression : Progression { private class TestWaitable : Waitable, IProgressReporter {
/// <summary>will be triggered to report when progress has been achieved</summary>
public event EventHandler<ProgressReportEventArgs> AsyncProgressChanged;
/// <summary>Changes the testing progression's indicated progress</summary> /// <summary>Changes the testing progression's indicated progress</summary>
/// <param name="progress"> /// <param name="progress">
/// New progress to be reported by the testing progression /// New progress to be reported by the testing progression
/// </param> /// </param>
public void ChangeProgress(float progress) { public void ChangeProgress(float progress) {
OnAsyncProgressUpdated(progress); OnAsyncProgressChanged(progress);
} }
/// <summary>Transitions the progression into the ended state</summary> /// <summary>Transitions the progression into the ended state</summary>
@ -109,9 +112,32 @@ namespace Nuclex.Support.Tracking {
OnAsyncEnded(); OnAsyncEnded();
} }
/// <summary>Fires the progress update event</summary>
/// <param name="progress">Progress to report (ranging from 0.0 to 1.0)</param>
/// <remarks>
/// Informs the observers of this progression about the achieved progress.
/// </remarks>
protected virtual void OnAsyncProgressChanged(float progress) {
OnAsyncProgressChanged(new ProgressReportEventArgs(progress));
} }
#endregion // class TestProgression /// <summary>Fires the progress update event</summary>
/// <param name="eventArguments">Progress to report (ranging from 0.0 to 1.0)</param>
/// <remarks>
/// Informs the observers of this progression about the achieved progress.
/// Allows for classes derived from the Progression class to easily provide
/// a custom event arguments class that has been derived from the
/// Progression's ProgressUpdateEventArgs class.
/// </remarks>
protected virtual void OnAsyncProgressChanged(ProgressReportEventArgs eventArguments) {
EventHandler<ProgressReportEventArgs> copy = AsyncProgressChanged;
if(copy != null)
copy(this, eventArguments);
}
}
#endregion // class TestWaitable
/// <summary>Initialization routine executed before each test is run</summary> /// <summary>Initialization routine executed before each test is run</summary>
[SetUp] [SetUp]
@ -122,19 +148,19 @@ namespace Nuclex.Support.Tracking {
/// <summary>Validates that the set progression properly sums the progress</summary> /// <summary>Validates that the set progression properly sums the progress</summary>
[Test] [Test]
public void TestSummedProgress() { public void TestSummedProgress() {
SetProgression<TestProgression> testSetProgression = SetProgression<TestWaitable> testSetProgression =
new SetProgression<TestProgression>( new SetProgression<TestWaitable>(
new TestProgression[] { new TestProgression(), new TestProgression() } new TestWaitable[] { new TestWaitable(), new TestWaitable() }
); );
ISetProgressionSubscriber mockedSubscriber = mockSubscriber(testSetProgression); ISetProgressionSubscriber mockedSubscriber = mockSubscriber(testSetProgression);
Expect.Once.On(mockedSubscriber). Expect.Once.On(mockedSubscriber).
Method("ProgressUpdated"). Method("ProgressChanged").
With( With(
new Matcher[] { new Matcher[] {
new NMock2.Matchers.TypeMatcher(typeof(SetProgression<TestProgression>)), new NMock2.Matchers.TypeMatcher(typeof(SetProgression<TestWaitable>)),
new ProgressUpdateEventArgsMatcher(new ProgressUpdateEventArgs(0.25f)) new ProgressUpdateEventArgsMatcher(new ProgressReportEventArgs(0.25f))
} }
); );
@ -146,33 +172,33 @@ namespace Nuclex.Support.Tracking {
/// <summary>Validates that the set progression respects the weights</summary> /// <summary>Validates that the set progression respects the weights</summary>
[Test] [Test]
public void TestWeightedSummedProgress() { public void TestWeightedSummedProgress() {
SetProgression<TestProgression> testSetProgression = SetProgression<TestWaitable> testSetProgression =
new SetProgression<TestProgression>( new SetProgression<TestWaitable>(
new WeightedProgression<TestProgression>[] { new WeightedProgression<TestWaitable>[] {
new WeightedProgression<TestProgression>(new TestProgression(), 1.0f), new WeightedProgression<TestWaitable>(new TestWaitable(), 1.0f),
new WeightedProgression<TestProgression>(new TestProgression(), 2.0f) new WeightedProgression<TestWaitable>(new TestWaitable(), 2.0f)
} }
); );
ISetProgressionSubscriber mockedSubscriber = mockSubscriber(testSetProgression); ISetProgressionSubscriber mockedSubscriber = mockSubscriber(testSetProgression);
Expect.Once.On(mockedSubscriber). Expect.Once.On(mockedSubscriber).
Method("ProgressUpdated"). Method("ProgressChanged").
With( With(
new Matcher[] { new Matcher[] {
new NMock2.Matchers.TypeMatcher(typeof(SetProgression<TestProgression>)), new NMock2.Matchers.TypeMatcher(typeof(SetProgression<TestWaitable>)),
new ProgressUpdateEventArgsMatcher(new ProgressUpdateEventArgs(0.5f / 3.0f)) new ProgressUpdateEventArgsMatcher(new ProgressReportEventArgs(0.5f / 3.0f))
} }
); );
testSetProgression.Children[0].Progression.ChangeProgress(0.5f); testSetProgression.Children[0].Progression.ChangeProgress(0.5f);
Expect.Once.On(mockedSubscriber). Expect.Once.On(mockedSubscriber).
Method("ProgressUpdated"). Method("ProgressChanged").
With( With(
new Matcher[] { new Matcher[] {
new NMock2.Matchers.TypeMatcher(typeof(SetProgression<TestProgression>)), new NMock2.Matchers.TypeMatcher(typeof(SetProgression<TestWaitable>)),
new ProgressUpdateEventArgsMatcher(new ProgressUpdateEventArgs(0.5f)) new ProgressUpdateEventArgsMatcher(new ProgressReportEventArgs(0.5f))
} }
); );
@ -186,9 +212,9 @@ namespace Nuclex.Support.Tracking {
/// </summary> /// </summary>
[Test] [Test]
public void TestEndedEvent() { public void TestEndedEvent() {
SetProgression<TestProgression> testSetProgression = SetProgression<TestWaitable> testSetProgression =
new SetProgression<TestProgression>( new SetProgression<TestWaitable>(
new TestProgression[] { new TestProgression(), new TestProgression() } new TestWaitable[] { new TestWaitable(), new TestWaitable() }
); );
ISetProgressionSubscriber mockedSubscriber = mockSubscriber(testSetProgression); ISetProgressionSubscriber mockedSubscriber = mockSubscriber(testSetProgression);
@ -210,13 +236,13 @@ namespace Nuclex.Support.Tracking {
/// <summary>Mocks a subscriber for the events of a progression</summary> /// <summary>Mocks a subscriber for the events of a progression</summary>
/// <param name="progression">Progression to mock an event subscriber for</param> /// <param name="progression">Progression to mock an event subscriber for</param>
/// <returns>The mocked event subscriber</returns> /// <returns>The mocked event subscriber</returns>
private ISetProgressionSubscriber mockSubscriber(Progression progression) { private ISetProgressionSubscriber mockSubscriber(Waitable progression) {
ISetProgressionSubscriber mockedSubscriber = ISetProgressionSubscriber mockedSubscriber =
this.mockery.NewMock<ISetProgressionSubscriber>(); this.mockery.NewMock<ISetProgressionSubscriber>();
progression.AsyncEnded += new EventHandler(mockedSubscriber.Ended); progression.AsyncEnded += new EventHandler(mockedSubscriber.Ended);
progression.AsyncProgressUpdated += (progression as IProgressReporter).AsyncProgressChanged +=
new EventHandler<ProgressUpdateEventArgs>(mockedSubscriber.ProgressUpdated); new EventHandler<ProgressReportEventArgs>(mockedSubscriber.ProgressChanged);
return mockedSubscriber; return mockedSubscriber;
} }

View File

@ -28,13 +28,11 @@ namespace Nuclex.Support.Tracking {
/// <summary>Forms a single progression from a set of progressions</summary> /// <summary>Forms a single progression from a set of progressions</summary>
/// <typeparam name="ProgressionType">Type of progressions to manage as a set</typeparam> /// <typeparam name="ProgressionType">Type of progressions to manage as a set</typeparam>
public class SetProgression<ProgressionType> : Progression, IDisposable public class SetProgression<ProgressionType> : Waitable, IDisposable, IProgressReporter
where ProgressionType : Progression { where ProgressionType : Waitable {
/// <summary>Performs common initialization for the public constructors</summary> /// <summary>will be triggered to report when progress has been achieved</summary>
private SetProgression() { public event EventHandler<ProgressReportEventArgs> AsyncProgressChanged;
this.children = new List<ObservedWeightedProgression<ProgressionType>>();
}
/// <summary>Initializes a new set progression</summary> /// <summary>Initializes a new set progression</summary>
/// <param name="childs">Progressions to track with this set</param> /// <param name="childs">Progressions to track with this set</param>
@ -85,6 +83,11 @@ namespace Nuclex.Support.Tracking {
} }
/// <summary>Performs common initialization for the public constructors</summary>
private SetProgression() {
this.children = new List<ObservedWeightedProgression<ProgressionType>>();
}
/// <summary>Immediately releases all resources owned by the object</summary> /// <summary>Immediately releases all resources owned by the object</summary>
public void Dispose() { public void Dispose() {
@ -124,6 +127,29 @@ namespace Nuclex.Support.Tracking {
} }
} }
/// <summary>Fires the progress update event</summary>
/// <param name="progress">Progress to report (ranging from 0.0 to 1.0)</param>
/// <remarks>
/// Informs the observers of this progression about the achieved progress.
/// </remarks>
protected virtual void OnAsyncProgressChanged(float progress) {
OnAsyncProgressChanged(new ProgressReportEventArgs(progress));
}
/// <summary>Fires the progress update event</summary>
/// <param name="eventArguments">Progress to report (ranging from 0.0 to 1.0)</param>
/// <remarks>
/// Informs the observers of this progression about the achieved progress.
/// Allows for classes derived from the Progression class to easily provide
/// a custom event arguments class that has been derived from the
/// Progression's ProgressUpdateEventArgs class.
/// </remarks>
protected virtual void OnAsyncProgressChanged(ProgressReportEventArgs eventArguments) {
EventHandler<ProgressReportEventArgs> copy = AsyncProgressChanged;
if(copy != null)
copy(this, eventArguments);
}
/// <summary> /// <summary>
/// Called when the progress of one of the observed progressions changes /// Called when the progress of one of the observed progressions changes
/// </summary> /// </summary>
@ -142,7 +168,7 @@ namespace Nuclex.Support.Tracking {
totalProgress /= this.totalWeight; totalProgress /= this.totalWeight;
// Send out the progress update // Send out the progress update
OnAsyncProgressUpdated(totalProgress); OnAsyncProgressChanged(totalProgress);
} }
/// <summary> /// <summary>

View File

@ -23,33 +23,34 @@ using System.Threading;
namespace Nuclex.Support.Tracking { namespace Nuclex.Support.Tracking {
/// <summary>Base class for actions that give an indication of their progress</summary> /// <summary>Base class for actions on which that give an indication of their progress</summary>
/// <remarks> /// <remarks>
/// <para> /// <para>
/// By encapsulating long-running operations which will ideally be running in /// By encapsulating long-running operations which will ideally be running in
/// a background thread in a class that's derived from Progression you can wait /// a background thread in a class that's derived from <see cref="Waitable" />
/// for the completion of the operation and receive feedback on the achieved /// you can wait for the completion of the operation and optionally even receive
/// progress. This is useful for displaying a progress bar, loading screen or /// feedback on the achieved progress. This is useful for displaying a progress
/// some other means of entertaining the user while he waits for the operation to /// bar, loading screen or some other means of entertaining the user while he
/// complete. It is also possible to register callbacks which will be fired once /// waits for the task to complete.
/// the progression has ended.
/// </para> /// </para>
/// <para> /// <para>
/// This class deliberately does not provide an Execute() method or anything similar /// You can register callbacks which will be fired once the <see cref="Waitable" />
/// to clearly seperate the initiation of an operation from just monitoring it. /// task has completed. This class deliberately does not provide an Execute()
/// By omitting an Execute() method, it also becomes possible to construct a /// method or anything similar to clearly seperate the initiation of an operation
/// progression just-in-time when it is explicitely asked for. /// from just monitoring it. By omitting an Execute() method, it also becomes
/// possible to construct a progression just-in-time when it is explicitely being
/// asked for.
/// </para> /// </para>
/// </remarks> /// </remarks>
public abstract class Progression { public abstract class Waitable {
#region class EndedDummyProgression #region class EndedDummyProgression
/// <summary>Dummy progression which always is in the 'ended' state</summary> /// <summary>Dummy progression which always is in the 'ended' state</summary>
private class EndedDummyProgression : Progression { private class EndedDummyWaitable : Waitable {
/// <summary>Initializes a new ended dummy progression</summary> /// <summary>Initializes a new ended dummy progression</summary>
public EndedDummyProgression() { public EndedDummyWaitable() {
OnAsyncEnded(); OnAsyncEnded();
} }
@ -63,10 +64,7 @@ namespace Nuclex.Support.Tracking {
/// when a progression that's lazily created is accessed after the original /// when a progression that's lazily created is accessed after the original
/// operation has ended already. /// operation has ended already.
/// </remarks> /// </remarks>
public static readonly Progression EndedDummy = new EndedDummyProgression(); public static readonly Waitable EndedDummy = new EndedDummyWaitable();
/// <summary>will be triggered to report when progress has been achieved</summary>
public event EventHandler<ProgressUpdateEventArgs> AsyncProgressUpdated;
/// <summary>Will be triggered when the progression has ended</summary> /// <summary>Will be triggered when the progression has ended</summary>
public event EventHandler AsyncEnded; public event EventHandler AsyncEnded;
@ -102,29 +100,6 @@ namespace Nuclex.Support.Tracking {
} }
} }
/// <summary>Fires the progress update event</summary>
/// <param name="progress">Progress to report (ranging from 0.0 to 1.0)</param>
/// <remarks>
/// Informs the observers of this progression about the achieved progress.
/// </remarks>
protected virtual void OnAsyncProgressUpdated(float progress) {
OnAsyncProgressUpdated(new ProgressUpdateEventArgs(progress));
}
/// <summary>Fires the progress update event</summary>
/// <param name="eventArguments">Progress to report (ranging from 0.0 to 1.0)</param>
/// <remarks>
/// Informs the observers of this progression about the achieved progress.
/// Allows for classes derived from the Progression class to easily provide
/// a custom event arguments class that has been derived from the
/// Progression's ProgressUpdateEventArgs class.
/// </remarks>
protected virtual void OnAsyncProgressUpdated(ProgressUpdateEventArgs eventArguments) {
EventHandler<ProgressUpdateEventArgs> copy = AsyncProgressUpdated;
if(copy != null)
copy(this, eventArguments);
}
/// <summary>Fires the AsyncEnded event</summary> /// <summary>Fires the AsyncEnded event</summary>
/// <remarks> /// <remarks>
/// <para> /// <para>

View File

@ -24,7 +24,7 @@ using System.Collections.Generic;
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>
public class WeightedProgression<ProgressionType> where ProgressionType : Progression { public class WeightedProgression<ProgressionType> where ProgressionType : Waitable {
/// <summary> /// <summary>
/// Initializes a new weighted progression with a default weight of 1.0 /// Initializes a new weighted progression with a default weight of 1.0