From 7dbfc3c42206e70f68608a95faa8b760aa86c804 Mon Sep 17 00:00:00 2001 From: Markus Ewald Date: Wed, 26 Mar 2008 21:03:49 +0000 Subject: [PATCH] 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 --- Nuclex.Support (x86).csproj | 3 +- Source/Scheduling/QueueOperation.Test.cs | 50 ++++++++--- Source/Scheduling/QueueOperation.cs | 62 +++++++++---- Source/Tracking/IProgressReporter.cs | 34 +++++++ Source/Tracking/IStatusReporter.cs | 2 +- .../Internal/ObservedWeightedProgression.cs | 27 ++++-- .../WeightedProgressionWrapperCollection.cs | 2 +- Source/Tracking/ProgressUpdateEventArgs.cs | 4 +- Source/Tracking/ProgressionTracker.Test.cs | 64 ++++++++++---- Source/Tracking/ProgressionTracker.cs | 44 +++++----- Source/Tracking/Request.cs | 2 +- Source/Tracking/SetProgression.Test.cs | 88 ++++++++++++------- Source/Tracking/SetProgression.cs | 40 +++++++-- .../Tracking/{Progression.cs => Waitable.cs} | 57 ++++-------- Source/Tracking/WeightedProgression.cs | 2 +- 15 files changed, 321 insertions(+), 160 deletions(-) create mode 100644 Source/Tracking/IProgressReporter.cs rename Source/Tracking/{Progression.cs => Waitable.cs} (66%) diff --git a/Nuclex.Support (x86).csproj b/Nuclex.Support (x86).csproj index a8b4444..ea47a40 100644 --- a/Nuclex.Support (x86).csproj +++ b/Nuclex.Support (x86).csproj @@ -147,9 +147,10 @@ + - + ProgressionTracker.cs diff --git a/Source/Scheduling/QueueOperation.Test.cs b/Source/Scheduling/QueueOperation.Test.cs index 1f0da41..fdf2d4e 100644 --- a/Source/Scheduling/QueueOperation.Test.cs +++ b/Source/Scheduling/QueueOperation.Test.cs @@ -43,7 +43,7 @@ namespace Nuclex.Support.Scheduling { /// Called when the queue operations's progress changes /// Queue operation whose progress has changed /// Contains the new progress achieved - void ProgressUpdated(object sender, ProgressUpdateEventArgs e); + void ProgressChanged(object sender, ProgressReportEventArgs e); /// Called when the queue operation has ended /// Queue operation that as ended @@ -61,7 +61,7 @@ namespace Nuclex.Support.Scheduling { /// Initializes a new ProgressUpdateEventArgsMatcher /// Expected progress update event arguments - public ProgressUpdateEventArgsMatcher(ProgressUpdateEventArgs expected) { + public ProgressUpdateEventArgsMatcher(ProgressReportEventArgs expected) { this.expected = expected; } @@ -73,7 +73,7 @@ namespace Nuclex.Support.Scheduling { /// True if the actual value matches the expected value; otherwise false /// public override bool Matches(object actualAsObject) { - ProgressUpdateEventArgs actual = (actualAsObject as ProgressUpdateEventArgs); + ProgressReportEventArgs actual = (actualAsObject as ProgressReportEventArgs); if(actual == null) return false; @@ -87,7 +87,7 @@ namespace Nuclex.Support.Scheduling { } /// Expected progress update event args value - private ProgressUpdateEventArgs expected; + private ProgressReportEventArgs expected; } @@ -96,7 +96,10 @@ namespace Nuclex.Support.Scheduling { #region class TestOperation /// Progression used for testing in this unit test - private class TestOperation : Operation { + private class TestOperation : Operation, IProgressReporter { + + /// will be triggered to report when progress has been achieved + public event EventHandler AsyncProgressChanged; /// Begins executing the operation. Yeah, sure :) public override void Start() { } @@ -118,7 +121,7 @@ namespace Nuclex.Support.Scheduling { /// New progress to be reported by the testing progression /// public void ChangeProgress(float progress) { - OnAsyncProgressUpdated(progress); + OnAsyncProgressChanged(progress); } /// @@ -130,6 +133,29 @@ namespace Nuclex.Support.Scheduling { throw this.exception; } + /// Fires the progress update event + /// Progress to report (ranging from 0.0 to 1.0) + /// + /// Informs the observers of this progression about the achieved progress. + /// + protected virtual void OnAsyncProgressChanged(float progress) { + OnAsyncProgressChanged(new ProgressReportEventArgs(progress)); + } + + /// Fires the progress update event + /// Progress to report (ranging from 0.0 to 1.0) + /// + /// 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. + /// + protected virtual void OnAsyncProgressChanged(ProgressReportEventArgs eventArguments) { + EventHandler copy = AsyncProgressChanged; + if(copy != null) + copy(this, eventArguments); + } + /// Exception that has occured in the background process private volatile Exception exception; @@ -159,22 +185,22 @@ namespace Nuclex.Support.Scheduling { testQueueOperation.Start(); Expect.Once.On(mockedSubscriber). - Method("ProgressUpdated"). + Method("ProgressChanged"). With( new Matcher[] { new NMock2.Matchers.TypeMatcher(typeof(QueueOperation)), - new ProgressUpdateEventArgsMatcher(new ProgressUpdateEventArgs(0.25f)) + new ProgressUpdateEventArgsMatcher(new ProgressReportEventArgs(0.25f)) } ); operation1.ChangeProgress(0.5f); Expect.Once.On(mockedSubscriber). - Method("ProgressUpdated"). + Method("ProgressChanged"). With( new Matcher[] { new NMock2.Matchers.TypeMatcher(typeof(QueueOperation)), - new ProgressUpdateEventArgsMatcher(new ProgressUpdateEventArgs(0.5f)) + new ProgressUpdateEventArgsMatcher(new ProgressReportEventArgs(0.5f)) } ); @@ -191,8 +217,8 @@ namespace Nuclex.Support.Scheduling { this.mockery.NewMock(); operation.AsyncEnded += new EventHandler(mockedSubscriber.Ended); - operation.AsyncProgressUpdated += - new EventHandler(mockedSubscriber.ProgressUpdated); + (operation as IProgressReporter).AsyncProgressChanged += + new EventHandler(mockedSubscriber.ProgressChanged); return mockedSubscriber; } diff --git a/Source/Scheduling/QueueOperation.cs b/Source/Scheduling/QueueOperation.cs index d810919..1cba412 100644 --- a/Source/Scheduling/QueueOperation.cs +++ b/Source/Scheduling/QueueOperation.cs @@ -32,15 +32,8 @@ namespace Nuclex.Support.Scheduling { public class QueueOperation : Operation where OperationType : Operation { - /// Initializes a new queue operation - private QueueOperation() { - this.asyncOperationEndedDelegate = new EventHandler(asyncOperationEnded); - this.asyncOperationProgressUpdatedDelegate = new EventHandler( - asyncOperationProgressUpdated - ); - - this.children = new List>(); - } + /// will be triggered to report when progress has been achieved + public event EventHandler AsyncProgressUpdated; /// Initializes a new queue operation with default weights /// Child operations to execute in this operation @@ -74,6 +67,16 @@ namespace Nuclex.Support.Scheduling { } + /// Initializes a new queue operation + private QueueOperation() { + this.asyncOperationEndedDelegate = new EventHandler(asyncOperationEnded); + this.asyncOperationProgressChangedDelegate = new EventHandler( + asyncOperationProgressChanged + ); + + this.children = new List>(); + } + /// Provides access to the child operations of this queue public IList> Children { get { return this.children; } @@ -93,6 +96,29 @@ namespace Nuclex.Support.Scheduling { throw this.exception; } + /// Fires the progress update event + /// Progress to report (ranging from 0.0 to 1.0) + /// + /// Informs the observers of this progression about the achieved progress. + /// + protected virtual void OnAsyncProgressChanged(float progress) { + OnAsyncProgressChanged(new ProgressReportEventArgs(progress)); + } + + /// Fires the progress update event + /// Progress to report (ranging from 0.0 to 1.0) + /// + /// 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. + /// + protected virtual void OnAsyncProgressChanged(ProgressReportEventArgs eventArguments) { + EventHandler copy = AsyncProgressUpdated; + if(copy != null) + copy(this, eventArguments); + } + /// Prepares the current operation and calls its Begin() method /// /// 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; operation.AsyncEnded += this.asyncOperationEndedDelegate; - operation.AsyncProgressUpdated += this.asyncOperationProgressUpdatedDelegate; + + IProgressReporter progressReporter = operation as IProgressReporter; + if(progressReporter != null) + progressReporter.AsyncProgressChanged += this.asyncOperationProgressChangedDelegate; operation.Start(); } @@ -118,7 +147,10 @@ namespace Nuclex.Support.Scheduling { // Disconnect from the operation's events operation.AsyncEnded -= this.asyncOperationEndedDelegate; - operation.AsyncProgressUpdated -= this.asyncOperationProgressUpdatedDelegate; + + IProgressReporter progressReporter = operation as IProgressReporter; + if(progressReporter != null) + progressReporter.AsyncProgressChanged -= this.asyncOperationProgressChangedDelegate; try { operation.Join(); @@ -127,7 +159,7 @@ namespace Nuclex.Support.Scheduling { this.completedWeight += this.children[this.currentOperationIndex].Weight; // Trigger another progress update - OnAsyncProgressUpdated(this.completedWeight / this.totalWeight); + OnAsyncProgressChanged(this.completedWeight / this.totalWeight); } catch(Exception exception) { this.exception = exception; @@ -165,7 +197,7 @@ namespace Nuclex.Support.Scheduling { /// Called when currently executing operation makes progress /// Operation that has achieved progress /// Not used - private void asyncOperationProgressUpdated(object sender, ProgressUpdateEventArgs e) { + private void asyncOperationProgressChanged(object sender, ProgressReportEventArgs e) { // Determine the completed weight of the currently executing operation float currentOperationCompletedWeight = @@ -176,14 +208,14 @@ namespace Nuclex.Support.Scheduling { (this.completedWeight + currentOperationCompletedWeight) / this.totalWeight; // Done, we can send the actual progress to any event subscribers - OnAsyncProgressUpdated(progress); + OnAsyncProgressChanged(progress); } /// Delegate to the asyncOperationEnded() method private EventHandler asyncOperationEndedDelegate; /// Delegate to the asyncOperationProgressUpdated() method - private EventHandler asyncOperationProgressUpdatedDelegate; + private EventHandler asyncOperationProgressChangedDelegate; /// Operations being managed in the queue private List> children; /// Summed weight of all operations in the queue diff --git a/Source/Tracking/IProgressReporter.cs b/Source/Tracking/IProgressReporter.cs new file mode 100644 index 0000000..d0d67dc --- /dev/null +++ b/Source/Tracking/IProgressReporter.cs @@ -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 { + + /// Interface for processes that report their progress + public interface IProgressReporter { + + /// Triggered when the status of the process changes + event EventHandler AsyncProgressChanged; + + } + +} // namespace Nuclex.Support.Tracking diff --git a/Source/Tracking/IStatusReporter.cs b/Source/Tracking/IStatusReporter.cs index 1553fce..ade68af 100644 --- a/Source/Tracking/IStatusReporter.cs +++ b/Source/Tracking/IStatusReporter.cs @@ -27,7 +27,7 @@ namespace Nuclex.Support.Tracking { public interface IStatusReporter { /// Triggered when the status of the process changes - event EventHandler StatusChanged; + event EventHandler AsyncStatusChanged; } diff --git a/Source/Tracking/Internal/ObservedWeightedProgression.cs b/Source/Tracking/Internal/ObservedWeightedProgression.cs index d454d4a..0c7c8de 100644 --- a/Source/Tracking/Internal/ObservedWeightedProgression.cs +++ b/Source/Tracking/Internal/ObservedWeightedProgression.cs @@ -28,7 +28,7 @@ namespace Nuclex.Support.Tracking { /// Type of the progression that is being observed /// internal class ObservedWeightedProgression : IDisposable - where ProgressionType : Progression { + where ProgressionType : Waitable { /// Delegate for reporting progress updates public delegate void ReportDelegate(); @@ -69,8 +69,16 @@ namespace Nuclex.Support.Tracking { if(weightedProgression.Progression.Ended) { this.progress = 1.0f; } else { - this.weightedProgression.Progression.AsyncProgressUpdated += - new EventHandler(asyncProgressUpdated); + this.progressReporter = this.weightedProgression.Progression as IProgressReporter; + + if(this.progressReporter != null) { + this.asyncProgressChangedEventHandler = new EventHandler( + asyncProgressChanged + ); + + this.progressReporter.AsyncProgressChanged += + this.asyncProgressChangedEventHandler; + } } } @@ -119,7 +127,7 @@ namespace Nuclex.Support.Tracking { /// Called when the progress of the observed progression changes /// Progression whose progress has changed /// Contains the updated progress - private void asyncProgressUpdated(object sender, ProgressUpdateEventArgs e) { + private void asyncProgressChanged(object sender, ProgressReportEventArgs e) { this.progress = e.Progress; this.progressUpdateCallback(); } @@ -138,8 +146,12 @@ namespace Nuclex.Support.Tracking { this.weightedProgression.Progression.AsyncEnded -= new EventHandler(asyncEnded); - this.weightedProgression.Progression.AsyncProgressUpdated -= - new EventHandler(asyncProgressUpdated); + if(this.progressReporter != null) { + this.progressReporter.AsyncProgressChanged -= + this.asyncProgressChangedEventHandler; + + this.asyncProgressChangedEventHandler = null; + } this.endedCallback = null; this.progressUpdateCallback = null; @@ -150,6 +162,9 @@ namespace Nuclex.Support.Tracking { } + private EventHandler asyncProgressChangedEventHandler; + /// The observed progression's progress reporting interface + private IProgressReporter progressReporter; /// The weighted progression that is being observed private WeightedProgression weightedProgression; /// Callback to invoke when the progress updates diff --git a/Source/Tracking/Internal/WeightedProgressionWrapperCollection.cs b/Source/Tracking/Internal/WeightedProgressionWrapperCollection.cs index 84a1500..e67163d 100644 --- a/Source/Tracking/Internal/WeightedProgressionWrapperCollection.cs +++ b/Source/Tracking/Internal/WeightedProgressionWrapperCollection.cs @@ -51,7 +51,7 @@ namespace Nuclex.Support.Tracking { TransformingReadOnlyCollection< ObservedWeightedProgression, WeightedProgression > - where ProgressionType : Progression { + where ProgressionType : Waitable { /// Initializes a new weighted progression collection wrapper /// Items to be exposed as weighted progressions diff --git a/Source/Tracking/ProgressUpdateEventArgs.cs b/Source/Tracking/ProgressUpdateEventArgs.cs index 828d48a..5ab464b 100644 --- a/Source/Tracking/ProgressUpdateEventArgs.cs +++ b/Source/Tracking/ProgressUpdateEventArgs.cs @@ -24,11 +24,11 @@ using System.Collections.Generic; namespace Nuclex.Support.Tracking { /// Event arguments for a progress update notification - public class ProgressUpdateEventArgs : EventArgs { + public class ProgressReportEventArgs : EventArgs { /// Initializes the progress update informations /// Achieved progress ranging from 0.0 to 1.0 - public ProgressUpdateEventArgs(float progress) { + public ProgressReportEventArgs(float progress) { this.progress = progress; } diff --git a/Source/Tracking/ProgressionTracker.Test.cs b/Source/Tracking/ProgressionTracker.Test.cs index 568e54e..adc8cf8 100644 --- a/Source/Tracking/ProgressionTracker.Test.cs +++ b/Source/Tracking/ProgressionTracker.Test.cs @@ -41,7 +41,7 @@ namespace Nuclex.Support.Tracking { /// Called when the progression tracker's progress changes /// Progression tracker whose progress has changed /// Contains the new progress achieved - void ProgressUpdated(object sender, ProgressUpdateEventArgs e); + void ProgressUpdated(object sender, ProgressReportEventArgs e); /// Called when the progression tracker's idle state changes /// Progression tracker whose idle state has changed @@ -59,7 +59,7 @@ namespace Nuclex.Support.Tracking { /// Initializes a new ProgressUpdateEventArgsMatcher /// Expected progress update event arguments - public ProgressUpdateEventArgsMatcher(ProgressUpdateEventArgs expected) { + public ProgressUpdateEventArgsMatcher(ProgressReportEventArgs expected) { this.expected = expected; } @@ -71,7 +71,7 @@ namespace Nuclex.Support.Tracking { /// True if the actual value matches the expected value; otherwise false /// public override bool Matches(object actualAsObject) { - ProgressUpdateEventArgs actual = (actualAsObject as ProgressUpdateEventArgs); + ProgressReportEventArgs actual = (actualAsObject as ProgressReportEventArgs); if(actual == null) return false; @@ -85,7 +85,7 @@ namespace Nuclex.Support.Tracking { } /// Expected progress update event args value - private ProgressUpdateEventArgs expected; + private ProgressReportEventArgs expected; } @@ -94,14 +94,17 @@ namespace Nuclex.Support.Tracking { #region class TestProgression /// Progression used for testing in this unit test - private class TestProgression : Progression { + private class TestProgression : Waitable { + + /// will be triggered to report when progress has been achieved + public event EventHandler AsyncProgressChanged; /// Changes the testing progression's indicated progress /// /// New progress to be reported by the testing progression /// public void ChangeProgress(float progress) { - OnAsyncProgressUpdated(progress); + OnAsyncProgressChanged(progress); } /// Transitions the progression into the ended state @@ -109,6 +112,29 @@ namespace Nuclex.Support.Tracking { OnAsyncEnded(); } + /// Fires the progress update event + /// Progress to report (ranging from 0.0 to 1.0) + /// + /// Informs the observers of this progression about the achieved progress. + /// + protected virtual void OnAsyncProgressChanged(float progress) { + OnAsyncProgressChanged(new ProgressReportEventArgs(progress)); + } + + /// Fires the progress update event + /// Progress to report (ranging from 0.0 to 1.0) + /// + /// 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. + /// + protected virtual void OnAsyncProgressChanged(ProgressReportEventArgs eventArguments) { + EventHandler copy = AsyncProgressChanged; + if(copy != null) + copy(this, eventArguments); + } + } #endregion // class TestProgression @@ -135,7 +161,7 @@ namespace Nuclex.Support.Tracking { With( new Matcher[] { 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( new Matcher[] { 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( new Matcher[] { 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( new Matcher[] { 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( new Matcher[] { 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( new Matcher[] { 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); - tracker.Track(Progression.EndedDummy); + tracker.Track(Waitable.EndedDummy); this.mockery.VerifyAllExpectationsHaveBeenMet(); } @@ -267,7 +293,7 @@ namespace Nuclex.Support.Tracking { With( new Matcher[] { 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( new Matcher[] { 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). Method("ProgressUpdated"). With( new Matcher[] { 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 += (EventHandler)delegate(object sender, IdleStateEventArgs arguments) { - tracker.Track(Progression.EndedDummy); + tracker.Track(Waitable.EndedDummy); }; test1.End(); @@ -333,7 +359,7 @@ namespace Nuclex.Support.Tracking { new EventHandler(mockedSubscriber.IdleStateChanged); tracker.AsyncProgressUpdated += - new EventHandler(mockedSubscriber.ProgressUpdated); + new EventHandler(mockedSubscriber.ProgressUpdated); return mockedSubscriber; } diff --git a/Source/Tracking/ProgressionTracker.cs b/Source/Tracking/ProgressionTracker.cs index 399d14f..441cefc 100644 --- a/Source/Tracking/ProgressionTracker.cs +++ b/Source/Tracking/ProgressionTracker.cs @@ -50,7 +50,7 @@ namespace Nuclex.Support.Tracking { /// the specified progression /// /// Progression to match against - public ProgressionMatcher(Progression toMatch) { + public ProgressionMatcher(Waitable toMatch) { this.toMatch = toMatch; } @@ -59,12 +59,12 @@ namespace Nuclex.Support.Tracking { /// progression of the instance /// /// Progression to match to the comparison progression - public bool Matches(ObservedWeightedProgression other) { + public bool Matches(ObservedWeightedProgression other) { return ReferenceEquals(other.WeightedProgression.Progression, this.toMatch); } /// Progression this instance compares against - private Progression toMatch; + private Waitable toMatch; } @@ -80,18 +80,18 @@ namespace Nuclex.Support.Tracking { public event EventHandler AsyncIdleStateChanged; /// Triggered when the total progress has changed - public event EventHandler AsyncProgressUpdated; + public event EventHandler AsyncProgressUpdated; /// Initializes a new progression tracker public ProgressionTracker() { - this.trackedProgressions = new List>(); + this.trackedProgressions = new List>(); this.idle = true; this.asyncEndedDelegate = - new ObservedWeightedProgression.ReportDelegate(asyncEnded); + new ObservedWeightedProgression.ReportDelegate(asyncEnded); this.asyncProgressUpdatedDelegate = - new ObservedWeightedProgression.ReportDelegate(asyncProgressUpdated); + new ObservedWeightedProgression.ReportDelegate(asyncProgressUpdated); } @@ -115,14 +115,14 @@ namespace Nuclex.Support.Tracking { /// Begins tracking the specified progression /// Progression to be tracked - public void Track(Progression progression) { + public void Track(Waitable progression) { Track(progression, 1.0f); } /// Begins tracking the specified progression /// Progression to be tracked /// Weight to assign to this progression - 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 // 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 // before the progression has been added to the tracked progressions list. this.trackedProgressions.Add( - new ObservedWeightedProgression( - new WeightedProgression(progression, weight), + new ObservedWeightedProgression( + new WeightedProgression(progression, weight), this.asyncProgressUpdatedDelegate, this.asyncEndedDelegate ) @@ -167,9 +167,9 @@ namespace Nuclex.Support.Tracking { // Construct a new progression observer and add the progression to our // list of tracked progressions. - ObservedWeightedProgression observedProgression = - new ObservedWeightedProgression( - new WeightedProgression(progression, weight), + ObservedWeightedProgression observedProgression = + new ObservedWeightedProgression( + new WeightedProgression(progression, weight), this.asyncProgressUpdatedDelegate, this.asyncEndedDelegate ); @@ -202,12 +202,12 @@ namespace Nuclex.Support.Tracking { /// Stops tracking the specified progression /// Progression to stop tracking of - public void Untrack(Progression progression) { + public void Untrack(Waitable progression) { lock(this.trackedProgressions) { // Locate the object to be untracked in our collection int removeIndex = this.trackedProgressions.FindIndex( - new Predicate>( + new Predicate>( new ProgressionMatcher(progression).Matches ) ); @@ -216,7 +216,7 @@ namespace Nuclex.Support.Tracking { // Remove and dispose the progression the user wants to untrack { - ObservedWeightedProgression wrappedProgression = + ObservedWeightedProgression wrappedProgression = this.trackedProgressions[removeIndex]; this.trackedProgressions.RemoveAt(removeIndex); @@ -266,9 +266,9 @@ namespace Nuclex.Support.Tracking { /// Fires the AsyncProgressUpdated event /// New progress to report protected virtual void OnAsyncProgressUpdated(float progress) { - EventHandler copy = AsyncProgressUpdated; + EventHandler copy = AsyncProgressUpdated; if(copy != null) - copy(this, new ProgressUpdateEventArgs(progress)); + copy(this, new ProgressReportEventArgs(progress)); } /// Recalculates the total progress of the tracker @@ -351,11 +351,11 @@ namespace Nuclex.Support.Tracking { /// Total weight of all progressions being tracked private volatile float totalWeight; /// Progressions being tracked by this tracker - private List> trackedProgressions; + private List> trackedProgressions; /// Delegate for the asyncEnded() method - private ObservedWeightedProgression.ReportDelegate asyncEndedDelegate; + private ObservedWeightedProgression.ReportDelegate asyncEndedDelegate; /// Delegate for the asyncProgressUpdated() method - private ObservedWeightedProgression.ReportDelegate asyncProgressUpdatedDelegate; + private ObservedWeightedProgression.ReportDelegate asyncProgressUpdatedDelegate; } diff --git a/Source/Tracking/Request.cs b/Source/Tracking/Request.cs index 25d9d7d..492e7b6 100644 --- a/Source/Tracking/Request.cs +++ b/Source/Tracking/Request.cs @@ -37,7 +37,7 @@ namespace Nuclex.Support.Tracking { /// OnAsyncEnded(), no matter what the outcome of your background operation is. /// /// - public abstract class Request : Progression { + public abstract class Request : Waitable { #region class EndedDummyRequest diff --git a/Source/Tracking/SetProgression.Test.cs b/Source/Tracking/SetProgression.Test.cs index 67e8cdb..097c474 100644 --- a/Source/Tracking/SetProgression.Test.cs +++ b/Source/Tracking/SetProgression.Test.cs @@ -41,7 +41,7 @@ namespace Nuclex.Support.Tracking { /// Called when the set progression's progress changes /// Set progression whose progress has changed /// Contains the new progress achieved - void ProgressUpdated(object sender, ProgressUpdateEventArgs e); + void ProgressChanged(object sender, ProgressReportEventArgs e); /// Called when the set progression has ended /// Set progression that as ended @@ -59,7 +59,7 @@ namespace Nuclex.Support.Tracking { /// Initializes a new ProgressUpdateEventArgsMatcher /// Expected progress update event arguments - public ProgressUpdateEventArgsMatcher(ProgressUpdateEventArgs expected) { + public ProgressUpdateEventArgsMatcher(ProgressReportEventArgs expected) { this.expected = expected; } @@ -71,7 +71,7 @@ namespace Nuclex.Support.Tracking { /// True if the actual value matches the expected value; otherwise false /// public override bool Matches(object actualAsObject) { - ProgressUpdateEventArgs actual = (actualAsObject as ProgressUpdateEventArgs); + ProgressReportEventArgs actual = (actualAsObject as ProgressReportEventArgs); if(actual == null) return false; @@ -85,23 +85,26 @@ namespace Nuclex.Support.Tracking { } /// Expected progress update event args value - private ProgressUpdateEventArgs expected; + private ProgressReportEventArgs expected; } #endregion // class ProgressUpdateEventArgsMatcher - #region class TestProgression + #region class TestWaitable /// Progression used for testing in this unit test - private class TestProgression : Progression { + private class TestWaitable : Waitable, IProgressReporter { + + /// will be triggered to report when progress has been achieved + public event EventHandler AsyncProgressChanged; /// Changes the testing progression's indicated progress /// /// New progress to be reported by the testing progression /// public void ChangeProgress(float progress) { - OnAsyncProgressUpdated(progress); + OnAsyncProgressChanged(progress); } /// Transitions the progression into the ended state @@ -109,9 +112,32 @@ namespace Nuclex.Support.Tracking { OnAsyncEnded(); } + /// Fires the progress update event + /// Progress to report (ranging from 0.0 to 1.0) + /// + /// Informs the observers of this progression about the achieved progress. + /// + protected virtual void OnAsyncProgressChanged(float progress) { + OnAsyncProgressChanged(new ProgressReportEventArgs(progress)); + } + + /// Fires the progress update event + /// Progress to report (ranging from 0.0 to 1.0) + /// + /// 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. + /// + protected virtual void OnAsyncProgressChanged(ProgressReportEventArgs eventArguments) { + EventHandler copy = AsyncProgressChanged; + if(copy != null) + copy(this, eventArguments); + } + } - #endregion // class TestProgression + #endregion // class TestWaitable /// Initialization routine executed before each test is run [SetUp] @@ -122,19 +148,19 @@ namespace Nuclex.Support.Tracking { /// Validates that the set progression properly sums the progress [Test] public void TestSummedProgress() { - SetProgression testSetProgression = - new SetProgression( - new TestProgression[] { new TestProgression(), new TestProgression() } + SetProgression testSetProgression = + new SetProgression( + new TestWaitable[] { new TestWaitable(), new TestWaitable() } ); ISetProgressionSubscriber mockedSubscriber = mockSubscriber(testSetProgression); Expect.Once.On(mockedSubscriber). - Method("ProgressUpdated"). + Method("ProgressChanged"). With( new Matcher[] { - new NMock2.Matchers.TypeMatcher(typeof(SetProgression)), - new ProgressUpdateEventArgsMatcher(new ProgressUpdateEventArgs(0.25f)) + new NMock2.Matchers.TypeMatcher(typeof(SetProgression)), + new ProgressUpdateEventArgsMatcher(new ProgressReportEventArgs(0.25f)) } ); @@ -146,33 +172,33 @@ namespace Nuclex.Support.Tracking { /// Validates that the set progression respects the weights [Test] public void TestWeightedSummedProgress() { - SetProgression testSetProgression = - new SetProgression( - new WeightedProgression[] { - new WeightedProgression(new TestProgression(), 1.0f), - new WeightedProgression(new TestProgression(), 2.0f) + SetProgression testSetProgression = + new SetProgression( + new WeightedProgression[] { + new WeightedProgression(new TestWaitable(), 1.0f), + new WeightedProgression(new TestWaitable(), 2.0f) } ); ISetProgressionSubscriber mockedSubscriber = mockSubscriber(testSetProgression); Expect.Once.On(mockedSubscriber). - Method("ProgressUpdated"). + Method("ProgressChanged"). With( new Matcher[] { - new NMock2.Matchers.TypeMatcher(typeof(SetProgression)), - new ProgressUpdateEventArgsMatcher(new ProgressUpdateEventArgs(0.5f / 3.0f)) + new NMock2.Matchers.TypeMatcher(typeof(SetProgression)), + new ProgressUpdateEventArgsMatcher(new ProgressReportEventArgs(0.5f / 3.0f)) } ); testSetProgression.Children[0].Progression.ChangeProgress(0.5f); Expect.Once.On(mockedSubscriber). - Method("ProgressUpdated"). + Method("ProgressChanged"). With( new Matcher[] { - new NMock2.Matchers.TypeMatcher(typeof(SetProgression)), - new ProgressUpdateEventArgsMatcher(new ProgressUpdateEventArgs(0.5f)) + new NMock2.Matchers.TypeMatcher(typeof(SetProgression)), + new ProgressUpdateEventArgsMatcher(new ProgressReportEventArgs(0.5f)) } ); @@ -186,9 +212,9 @@ namespace Nuclex.Support.Tracking { /// [Test] public void TestEndedEvent() { - SetProgression testSetProgression = - new SetProgression( - new TestProgression[] { new TestProgression(), new TestProgression() } + SetProgression testSetProgression = + new SetProgression( + new TestWaitable[] { new TestWaitable(), new TestWaitable() } ); ISetProgressionSubscriber mockedSubscriber = mockSubscriber(testSetProgression); @@ -210,13 +236,13 @@ namespace Nuclex.Support.Tracking { /// Mocks a subscriber for the events of a progression /// Progression to mock an event subscriber for /// The mocked event subscriber - private ISetProgressionSubscriber mockSubscriber(Progression progression) { + private ISetProgressionSubscriber mockSubscriber(Waitable progression) { ISetProgressionSubscriber mockedSubscriber = this.mockery.NewMock(); progression.AsyncEnded += new EventHandler(mockedSubscriber.Ended); - progression.AsyncProgressUpdated += - new EventHandler(mockedSubscriber.ProgressUpdated); + (progression as IProgressReporter).AsyncProgressChanged += + new EventHandler(mockedSubscriber.ProgressChanged); return mockedSubscriber; } diff --git a/Source/Tracking/SetProgression.cs b/Source/Tracking/SetProgression.cs index 4d53f4e..f8391e1 100644 --- a/Source/Tracking/SetProgression.cs +++ b/Source/Tracking/SetProgression.cs @@ -28,13 +28,11 @@ namespace Nuclex.Support.Tracking { /// Forms a single progression from a set of progressions /// Type of progressions to manage as a set - public class SetProgression : Progression, IDisposable - where ProgressionType : Progression { + public class SetProgression : Waitable, IDisposable, IProgressReporter + where ProgressionType : Waitable { - /// Performs common initialization for the public constructors - private SetProgression() { - this.children = new List>(); - } + /// will be triggered to report when progress has been achieved + public event EventHandler AsyncProgressChanged; /// Initializes a new set progression /// Progressions to track with this set @@ -85,6 +83,11 @@ namespace Nuclex.Support.Tracking { } + /// Performs common initialization for the public constructors + private SetProgression() { + this.children = new List>(); + } + /// Immediately releases all resources owned by the object public void Dispose() { @@ -124,6 +127,29 @@ namespace Nuclex.Support.Tracking { } } + /// Fires the progress update event + /// Progress to report (ranging from 0.0 to 1.0) + /// + /// Informs the observers of this progression about the achieved progress. + /// + protected virtual void OnAsyncProgressChanged(float progress) { + OnAsyncProgressChanged(new ProgressReportEventArgs(progress)); + } + + /// Fires the progress update event + /// Progress to report (ranging from 0.0 to 1.0) + /// + /// 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. + /// + protected virtual void OnAsyncProgressChanged(ProgressReportEventArgs eventArguments) { + EventHandler copy = AsyncProgressChanged; + if(copy != null) + copy(this, eventArguments); + } + /// /// Called when the progress of one of the observed progressions changes /// @@ -142,7 +168,7 @@ namespace Nuclex.Support.Tracking { totalProgress /= this.totalWeight; // Send out the progress update - OnAsyncProgressUpdated(totalProgress); + OnAsyncProgressChanged(totalProgress); } /// diff --git a/Source/Tracking/Progression.cs b/Source/Tracking/Waitable.cs similarity index 66% rename from Source/Tracking/Progression.cs rename to Source/Tracking/Waitable.cs index 6f03e44..4dbc1a8 100644 --- a/Source/Tracking/Progression.cs +++ b/Source/Tracking/Waitable.cs @@ -23,33 +23,34 @@ using System.Threading; namespace Nuclex.Support.Tracking { - /// Base class for actions that give an indication of their progress + /// Base class for actions on which that give an indication of their progress /// /// /// 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 - /// for the completion of the operation and receive feedback on the achieved - /// progress. This is useful for displaying a progress bar, loading screen or - /// some other means of entertaining the user while he waits for the operation to - /// complete. It is also possible to register callbacks which will be fired once - /// the progression has ended. + /// a background thread in a class that's derived from + /// you can wait for the completion of the operation and optionally even receive + /// feedback on the achieved progress. This is useful for displaying a progress + /// bar, loading screen or some other means of entertaining the user while he + /// waits for the task to complete. /// /// - /// This class deliberately does not provide an Execute() method or anything similar - /// to clearly seperate the initiation of an operation from just monitoring it. - /// By omitting an Execute() method, it also becomes possible to construct a - /// progression just-in-time when it is explicitely asked for. + /// You can register callbacks which will be fired once the + /// task has completed. This class deliberately does not provide an Execute() + /// method or anything similar to clearly seperate the initiation of an operation + /// 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. /// /// - public abstract class Progression { + public abstract class Waitable { #region class EndedDummyProgression /// Dummy progression which always is in the 'ended' state - private class EndedDummyProgression : Progression { + private class EndedDummyWaitable : Waitable { /// Initializes a new ended dummy progression - public EndedDummyProgression() { + public EndedDummyWaitable() { OnAsyncEnded(); } @@ -63,10 +64,7 @@ namespace Nuclex.Support.Tracking { /// when a progression that's lazily created is accessed after the original /// operation has ended already. /// - public static readonly Progression EndedDummy = new EndedDummyProgression(); - - /// will be triggered to report when progress has been achieved - public event EventHandler AsyncProgressUpdated; + public static readonly Waitable EndedDummy = new EndedDummyWaitable(); /// Will be triggered when the progression has ended public event EventHandler AsyncEnded; @@ -102,29 +100,6 @@ namespace Nuclex.Support.Tracking { } } - /// Fires the progress update event - /// Progress to report (ranging from 0.0 to 1.0) - /// - /// Informs the observers of this progression about the achieved progress. - /// - protected virtual void OnAsyncProgressUpdated(float progress) { - OnAsyncProgressUpdated(new ProgressUpdateEventArgs(progress)); - } - - /// Fires the progress update event - /// Progress to report (ranging from 0.0 to 1.0) - /// - /// 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. - /// - protected virtual void OnAsyncProgressUpdated(ProgressUpdateEventArgs eventArguments) { - EventHandler copy = AsyncProgressUpdated; - if(copy != null) - copy(this, eventArguments); - } - /// Fires the AsyncEnded event /// /// diff --git a/Source/Tracking/WeightedProgression.cs b/Source/Tracking/WeightedProgression.cs index 8fe6c63..ee49e30 100644 --- a/Source/Tracking/WeightedProgression.cs +++ b/Source/Tracking/WeightedProgression.cs @@ -24,7 +24,7 @@ using System.Collections.Generic; namespace Nuclex.Support.Tracking { /// Progression with an associated weight for the total progress - public class WeightedProgression where ProgressionType : Progression { + public class WeightedProgression where ProgressionType : Waitable { /// /// Initializes a new weighted progression with a default weight of 1.0