using System; using System.Collections.Generic; using System.Text; namespace Nuclex.Support.Tracking { /// Progression being observed by another class /// /// Type of the progression that is being observed /// internal class ObservedProgression : IDisposable where ProgressionType : Progression { /// Delegate for reporting progress updates public delegate void ReportDelegate(); /// Initializes a new observed progression /// Weighted progression being observed /// /// Callback to invoke when the progression's progress changes /// /// /// Callback to invoke when the progression has ended /// internal ObservedProgression( WeightedProgression weightedProgression, ReportDelegate progressUpdateCallback, ReportDelegate endedCallback ) { this.weightedProgression = weightedProgression; this.endedCallback = endedCallback; this.progressUpdateCallback = progressUpdateCallback; this.weightedProgression.Progression.AsyncEnded += new EventHandler(asyncEnded); this.weightedProgression.Progression.AsyncProgressUpdated += new EventHandler(asyncProgressUpdated); } /// Immediately releases all resources owned by the object public void Dispose() { asyncDisconnectEvents(); } /// Weighted progression being observed public WeightedProgression WeightedProgression { get { return this.weightedProgression; } } /// Amount of progress this progression has achieved so far public float Progress { get { return this.progress; } } /// Called when the observed progression has ended /// Progression that has ended /// Not used private void asyncEnded(object sender, EventArgs e) { ReportDelegate endedCallback = this.endedCallback; ReportDelegate progressUpdateCallback = this.progressUpdateCallback; asyncDisconnectEvents(); // We don't need those anymore! if(this.progress != 1.0f) { this.progress = 1.0f; progressUpdateCallback(); } endedCallback(); } /// 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) { this.progress = e.Progress; this.progressUpdateCallback(); } /// Unscribes from all events of the observed progression private void asyncDisconnectEvents() { // Make use of the double check locking idiom to avoid the costly lock when // the events have already been unsubscribed if(this.endedCallback != null) { // This is an internal class with special knowledge that there // is no risk of deadlock involved, so we don't need a fancy syncRoot! lock(this) { if(this.endedCallback != null) { this.weightedProgression.Progression.AsyncEnded -= new EventHandler(asyncEnded); this.weightedProgression.Progression.AsyncProgressUpdated -= new EventHandler(asyncProgressUpdated); this.endedCallback = null; this.progressUpdateCallback = null; } } } // endedCallback != null } /// The weighted progression that is being observed private WeightedProgression weightedProgression; /// Callback to invoke when the progress updates private volatile ReportDelegate progressUpdateCallback; /// Callback to invoke when the progression ends private volatile ReportDelegate endedCallback; /// Progress achieved so far private volatile float progress; } } // namespace Nuclex.Support.Tracking