|
// This file is part of the ProgressTracker library
// Copyright: Andreas Raczek
// This file is published under the The Code Project Open License (CPOL)
// See the file "CPOL.html" for the full license governing this code.
using System.ComponentModel;
using System.Threading;
using System;
namespace ProgressTracker
{
public class NewsCaster : INewsCaster
{
private readonly object memberLocker = new object();
private readonly object syncContextLocker = new object();
private IReporter rootReporter = null;
private SynchronizationContext syncContext = null;
private event PropertyChangedEventHandler propertyChanged;
private object propertyChangedLocker = new object();
ProgressDiagramDlg progressDiagramDlg = null;
public bool EnableProgressResultDlg
{
set
{
if (value) progressDiagramDlg = new ProgressDiagramDlg();
else progressDiagramDlg = null;
}
}
private event Action finishedEvent;
private readonly object finishedEventLocker = new object();
public event Action Finished
{
add
{
lock (this.finishedEventLocker)
{
this.finishedEvent += value;
}
}
remove
{
lock (this.finishedEventLocker)
{
this.finishedEvent -= value;
}
}
}
/// <summary>
/// Stores the time in ms when the progress was updated last time
/// </summary>
private int timeLastUpdate = 0;
/// <summary>
/// Start Time
/// </summary>
private int timeStart = 0;
/// <summary>
/// Will be set true once the root reporter indicates completion
/// of the assigned task.
/// </summary>
private bool isFinished = false;
/// <summary>
/// Contains the cached progress value that is queried
/// by <see cref="Progress"/>
private int progress = 0;
/// <summary>
/// Returns the cached value of the current progress
/// <see cref="progress"/>
/// </summary>
public int Progress
{
get
{
lock (this.memberLocker)
{
return progress;
}
}
}
private int getTimeElapsed()
{
return timeLastUpdate - timeStart;
}
public int TimeElapsed
{
get
{
lock (this.memberLocker)
{
return getTimeElapsed();
}
}
}
/// <summary>
/// </summary>
private int getTimeEstimated()
{
int timeElapsed = timeLastUpdate - timeStart;
if (timeElapsed <= 0) return -1;
if (progress <= 0) return -1;
return timeElapsed * 100 / progress;
}
public int TimeEstimated
{
get
{
lock (this.memberLocker)
{
return getTimeEstimated();
}
}
}
public NewsCaster()
{
lock (this.syncContextLocker)
{
this.syncContext = SynchronizationContext.Current;
if (this.syncContext == null)
{
// We are already in a worker thread and create a transparent
// synchronizationContext
this.syncContext = new SynchronizationContext();
}
}
}
public event PropertyChangedEventHandler PropertyChanged
{
add
{
lock (this.propertyChangedLocker)
{
this.propertyChanged += value;
}
}
remove
{
lock (this.propertyChangedLocker)
{
this.propertyChanged -= value;
}
}
}
public IReporter CreateReporter()
{
lock (this.memberLocker)
{
this.timeStart = System.Environment.TickCount;
this.timeLastUpdate = 0;
this.progress = 0;
this.isFinished = false;
this.rootReporter = new Reporter(this);
return this.rootReporter;
}
}
public void OnProgressChanged()
{
bool sendUpdate = false;
lock (this.memberLocker)
{
if (this.isFinished) return;
int nowTime = System.Environment.TickCount;
// 100 ms must be passed since last update
if (nowTime - this.timeLastUpdate > 100)
{
int progressNow = (int) ((this.rootReporter.GetProgress() * 100) + 0.5d);
if (progressNow > 100) progressNow = 100;
if (progressNow < 0) progressNow = 0;
this.timeLastUpdate = nowTime;
this.progress = progressNow;
if (null != progressDiagramDlg)
{
progressDiagramDlg.AddDataSet(
getTimeElapsed(),
progress,
getTimeEstimated());
}
sendUpdate = true;
}
}
if (sendUpdate) OnPropertyChanged("Progress");
}
/// <summary>
/// Internally triggered by OnProgressChanged() to raise PropertyChanged event
/// </summary>
private void OnPropertyChanged(string propertyName)
{
lock (this.syncContextLocker)
{
this.syncContext.Post(
new SendOrPostCallback((object state) =>
{
PropertyChangedEventHandler h = null;
lock (this.propertyChangedLocker)
{
h = this.propertyChanged;
}
if (h != null)
{
h(this, new PropertyChangedEventArgs(propertyName));
}
}),
null);
}
}
/// <summary>
/// Internally triggered by OnProgressChanged() to raise Finished event
/// </summary>
public void Finish()
{
lock (this.memberLocker)
{
this.isFinished = true;
// First make sure, progress is set to 100
this.progress = 100;
}
OnPropertyChanged("Progress");
// Then show statistics and raise Finished event
lock (this.syncContextLocker)
{
if (null != progressDiagramDlg)
{
this.syncContext.Post(
new SendOrPostCallback((object state) =>
{
progressDiagramDlg.Show();
}),
null);
}
this.syncContext.Post(
new SendOrPostCallback((object state) =>
{
Action h = null;
lock (this.finishedEventLocker)
{
h = this.finishedEvent;
}
if (h != null)
{
h();
}
}),
null);
}
}
}
}
|
By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.
If a file you wish to view isn't highlighted, and is a text file (not binary), please
let us know and we'll add colourisation support for it.
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.