DispatcherTimer for displaying seconds - wpf

I am trying to display a simple second counter. I have a dispatchertimer with a tick interval of 1 second and a textbox which I update in the tick handler with the current amount of seconds. There is a tiny amount of work in the tick handler, namely a call to 'tostring()' on some ints.
My issue is that the seconds are slower than they should be. Even if I set the interval to 100 milliseconds and make a check when elapsed, it is still slower than it should be. (over the course of a minute it is roughly 6 seconds slow).
Can anyone point me in the right direction for displaying a second counter that is accurate?
EDIT: Some code here (in .xaml.cs). It is taken from an example which works fine. The difference is that I am setting the Text property of a TextBox, rather than a Value property of another control.
...
this.timer.Interval = TimeSpan.FromMilliseconds(100);
...
private void OnDispatcherTimer_Tick(object sender, EventArgs e) {
if (this.currentValue > TimeSpan.Zero) {
this.currentValue = this.currentValue.Value.Subtract(TimeSpan.FromMilliseconds(100));
} else {
// stop timer etc
}
this.seconds.Text = this.currentValue.Value.Seconds.ToString();
}

Your way of keeping track of time is flawed. You're incrementing a counter each time the timer ticks, but there's no guarantee your timer will execute every 100 ms. And even if it did, you'd have to take into account the execution time of your code. Therefore, no matter what you do, your counter will drift.
What you must do is storing the date at which you started your counter. Then, every time the timer ticks, you compute the number of seconds that have elapsed:
private DateTime TimerStart { get; set; }
private void SomePlaceInYourCode()
{
this.TimerStart = DateTime.Now;
// Create and start the DispatcherTimer
}
private void OnDispatcherTimer_Tick(object sender, EventArgs e) {
var currentValue = DateTime.Now - this.TimerStart;
this.seconds.Text = currentValue.Seconds.ToString();
}

If you care about precise time a dispatchertimer is not good choice.
I thing you should separate counting seconds(time) and displaying on screen.
Use a System.Threading.Timer and use Dispatcher.BeginInvoke() in Timer callback.
simple example:
public partial class MainPage : PhoneApplicationPage
{
private DateTime _startDate;
private int _secondDuration;
private Timer _timer;
// Constructor
public MainPage()
{
InitializeComponent();
_startDate = DateTime.Now;
_secondDuration = 0;
_timer= new Timer(timerCallback, null, 0, 10);
}
private void timerCallback(object state)
{
var now = DateTime.Now;
if (now > _startDate + TimeSpan.FromSeconds(1))
{
_secondDuration += 1;
_startDate = now;
Dispatcher.BeginInvoke(() => { Counter.Text = _secondDuration.ToString(); });
}
}
}
After every 10 milisecond timer checks for one second has elapsed and print to textbox elapsed seconds
or you can do this like:
public partial class MainPage : PhoneApplicationPage
{
private Timer _timer;
private int _secondDuration;
// Constructor
public MainPage()
{
InitializeComponent();
_timer = new Timer(timerCallback, null, 0, 1000);
}
private void timerCallback(object state)
{
_secondDuration += 1;
Dispatcher.BeginInvoke(() => { Counter.Text = _secondDuration.ToString(); });
}
}

Related

Changing timer interval dynamically in Java 1.4

I have a timer task as shown below:
long timerSec = 5000;
TimerTask task1 = new TimerTask()
{
public void run()
{
//Some code...
System.out.println("Timer task...");
}
};
And a timer object as shown below:
Timer readFileTimer = new Timer();
I scheduled a task with 5 secs period between two successive task executions.
readFileTimer.scheduleAtFixedRate(task1, 0, timerSec);
Below line of code assigns new time period. I want to change the time period from 5 secs to n-secs (lets say 10 secs w.r.t. timerSec value).
timerSec = CalculateTimeForUpgrade(); //Get new timer interval period.
I tried below code, but didn't get the expected result.
readFileTimer.scheduleAtFixedRate(task1, 0, timerSec);
Please help. Thanks in advance.
Instead of starting the task at a fixed interval from the beginning, reschedule the task every time you finish it.
Something like this:
final Timer readFileTimer = new Timer();
readFileTimer.schedule(new MyTimerTask(), 0);
.......
private class MyTimerTask extends TimerTask() {
#Override
public void run() {
// Some code...
System.out.println("Timer task...");
if (readFileTimer!=null)
readFileTimer.schedule(new MyTimerTask(), CalculateTimeForUpgrade());
}
}

How to run a thread for specific time in c#? Something like executing the same code again and again like a script for 5 seconds

I want to run a thread, a small part of code to be executed for 5 seconds.
Execution should be only once, it should keep executing continuously for a specific time.
Note: It should not keep executing, something like a timer. Execution should be only once.
Real Problem:
There is a script called AHK. (Auto Hot Key).
It does some task like hiding a taskbar for specific time.
I am not allowed to modify the script.
I have to modify the same in application part(C#).
Sample Tried out codes:
void StartConnection()
{
stopwatch.Start();
Thread threadObj = new Thread(ThreadFunc);
threadObj.Start();
}
void ThreadFunc()
{
for (; stopwatch.Elapsed.TotalSeconds < 6; )
{
WindowsNativeCalls.HideTaskbar();
}
}
Is there any other dot net concept available to achieve this?
See if this fits your bill :
private void Button_Click(object sender, RoutedEventArgs e)
{
System.Threading.Tasks.Task.Factory.StartNew(() => { mycallBack(); });
}
private void mycallBack()
{
System.Diagnostics.Stopwatch stopWatch = new System.Diagnostics.Stopwatch();
stopWatch.Start();
while (true)
{
System.Diagnostics.Debug.WriteLine("Running !");
if (stopWatch.Elapsed.Seconds >= 5)
break;
}
System.Diagnostics.Debug.WriteLine("Done !");
}
You can use DispatcherTimer
private DispatcherTimer myTimer;
private void StartMyTimer()
{
if (myTimer != null)
myTimer.Stop();
myTimer = new DispatcherTimer();
myTimer.Interval = TimeSpan.FromSeconds(5);// You can change this for minutes, hours and etc
myTimer.Tick += myTimer_Tick;
myTimer.Start();
}
void myTimer_Tick(object sender, EventArgs e)
{
//Do something here every 5 seconds
}
I hope this helps.

Using System.Threading.Timer in Compact Framework

I am using a System.Threading.Timer in a CF project (Windows Embedded CE 6.0), VS2005 C#, .NET 2.0.
This timer is desired because there is no possibility of reentrancy when used like this:
private System.Threading.Timer mainTimer;
private void MainForm_Load(object sender, EventArgs e)
{
// other initializations
mainTimer = new System.Threading.Timer(new TimerCallback(timerMain_Tick),
null, 100, Timeout.Infinite);
}
Which is to say, dueTime parameter is used but period is not. As long as period is Timeout.Infinite, the timer will fire once only. The timer is made thread-safe by checking for the form's InvokeRequired property. Note the check for null. It relates to my question, which I am getting to quickly.
private void timerMain_Tick(object stateInfo)
{
if (mainTimer != null)
{
if (this.InvokeRequired)
{
this.Invoke((ThreadStart)delegate
{
TimerProcess();
});
}
else
{
TimerProcess();
}
}
}
The timer must restart itself before it exits.
private void TimerProcess()
{
try
{
// do work here
}
finally
{
// retrigger
mainTimer.Change(mainTimerInterval, Timeout.Infinite);
}
}
The problem I am having is gracefully stopping this darn thing.
private void MainForm_Closing(object sender, CancelEventArgs e)
{
// shut down timer
mainTimer.Change(Timeout.Infinite, Timeout.Infinite);
mainTimer.Dispose();
mainTimer = null;
}
About 3 times in 10, the timer fires anyway, and I get an Object Disposed error. The timer code is trying to invoke the timer method AFTER the check for null.
I suspect that the timer fires, and its thread is suspended while the form is closing. I tried a state machine enumeration:
Normal state Running
Form_Closing sets Stopping state and waits in a Thread.Sleep() loop for Stopped state
Timer sees Stopping and sets Stopped state (rather than retriggering itself)
Problem I had with this is that the timer thread would not preempt the form closing method, so get stuck in endless loop.
How to fix this problem? Note that in CF, there is no Dispose(WaitHandle) method.
Interesting problem. There do not seem to be many options with the Timer in the Compact Framework.
I'm not sure how your specific code works, so adding a single static Boolean value may or may not fix your issues.
Here is how I changed your code to accept a timerOK value. If this does not solve your problem, it could give you ideas on how to approach this.
private static bool timerOK;
private static long mainTimerInterval = 200;
private System.Threading.Timer mainTimer;
private void MainForm_Load(object sender, EventArgs e) {
timerOK = true;
mainTimer = new System.Threading.Timer(new TimerCallback(timerMain_Tick), null, 100, Timeout.Infinite);
}
private void MainForm_Closing(object sender, CancelEventArgs e) {
timerOK = false;
mainTimer.Change(Timeout.Infinite, Timeout.Infinite);
mainTimer.Dispose();
mainTimer = null;
}
private void timerMain_Tick(object stateInfo) {
if (timerOK && (mainTimer != null)) {
if (this.InvokeRequired) {
this.Invoke((ThreadStart)delegate {
TimerProcess();
});
} else {
TimerProcess();
}
}
}
private void TimerProcess() {
if (!timerOK) return;
try {
// do work here
} finally {
// retrigger
mainTimer.Change(mainTimerInterval, Timeout.Infinite);
}
}
I'm using MVP so my layout is a little different, but essentially I had the same two problems to fix:
Stop the timer firing after targets in the process method are disposed
Stop the timer firing DURING disposal
First one is easily fixed as pwrgreg007 shows above, just shutdown and null the timer sometime in your 'closing' process (before the form targets are disposed) and then do a null check at the start of your timer processing event.
Second issue is a bit trickier, even if the timer (and your form) are running at the start of your processing loop, nothing stops it getting shutdown mid way through the process as it is running on a different thread. To prevent this I created a lock to be used both during the timer execution AND the timer shutdown.
//simplified presenter
public class Presenter
{
private const int REFRESH_TIME_MILLISECONDS = 5000;
private view _view;
private Timer _timer;
private object _timerLock = new object();
//CTOR
public Presenter()
{
_view = new View();
Startup();
}
//spin up presenter
public void Startup(){
//bind view shutdown event
_view.ViewClosing += Shutdown;
//start timer
_timer = new Timer(DoTimerStuff, null, REFRESH_TIME_MILLISECONDS, Timeout.Infinite);
}
//spin down presenter
public void Shutdown()
{
//wait for any DoTimerStuff locks to expire
lock (_timerLock)
{
//stop the timer
_timer.Change(Timeout.Infinite, Timeout.Infinite);
_timer.Dispose();
_timer = null;
}
//close the view
_view.Shutdown();
}
//timer tick
private void DoTimerStuff(object state)
{
//grab a lock so we can ensure the timer doesn't get shutdown mid way through
lock (_timerLock)
{
//make sure the timer isn't shutdown (from form closing)
if (_timer == null) return;
//do your stuff here
_view.SomeInvokedCheckedProperty = "SomeValue";
//etc...
//schedule next timer execute (runs every runtime + refresh time)
_timer.Change(REFRESH_TIME_MILLISECONDS, Timeout.Infinite);
}
}
}
//simplified view
public class View : Form
{
//view properties (make sure they are invoke checked)
public SomeInvokedCheckedProperty {get;set;}
//Bound to ViewClosing
private void View_Closing(object sender, System.ComponentModel.CancelEventArgs e)
{
//stop the view closing itself
e.Cancel = true;
//tell the presenter to handle closing instead
if (ViewClosing != null) ViewClosing.Invoke();
}
}
That way..
The timer will wait to shutdown (holding up your form close) if DoTimerStuff() has the lock and is currently running
Conversely, DoTimerStuff() will wait if the timer shutdown has the lock and when it gets to continue it will correctly see the timer is shutdown (and do nothing).

Most efficient way of updating "3 minutes ago" type text in WPF

I currently use a valueconverters in XAML to display my viewmodel DateTime fields in "x minutes ago" format. I need to have them updated periodically without causing too much overhead. At any one time I have a dozen on screen, and a few dozen off screen. What is the best strategy?
In the constructor of the viewmodel object, have them register themselves to a static 'ViewRefresher' that periodically goes through all the objects and fires PropertyChanged handlers, on the registered fields.
Refresh the content/items control objects that are holding my objects
Something else?
I will go ahead and try both approaches above while I wait for answers and report back in case it helps someone else.
Update:
OK, thanks to csteinmueller for putting me on the events path. Much cleaner than registering/deregistering objects. I believe the following strategy should not be leaky.
public class DateTimeC: INotifyPropertyChanged
{
public DateTime DT {get; set;}
public event PropertyChangedEventHandler PropertyChanged;
public DateTimeC(DateTime dt)
{
DT = dt;
ViewRefresher.FiveSecondsTick += () =>
{ PropertyChanged(this, new PropertyChangedEventArgs("DT")); };
}
}
public delegate void TickHandler();
public static class ViewRefresher
{
private static DispatcherTimer dt = new DispatcherTimer();
private static int counter = 0;
public static event TickHandler FiveSecondsTick;
public static event TickHandler OneMinuteTick;
static ViewRefresher()
{
dt.Interval = TimeSpan.FromSeconds(5);
dt.Tick += Tick;
dt.Start();
}
private static void Tick(object sender, EventArgs e)
{
if (FiveSecondsTick != null)
FiveSecondsTick();
if (counter++ != 12) return;
counter = 0;
if (OneMinuteTick != null)
OneMinuteTick();
}
}
Would have been nice if I could derive from DateTime directly instead of inlining as a field, but it's sealed.
UPDATE 2: This does seem to have a memory leak after all. You need to unhook event for DateTimeC to be garbage-collected, or use a weak reference.
I would choose a System.Timer object togehther with your first approach (all ViewModels register to a collection or event in a static class)
Timer timer;
AutoResetEvent autoEvent = new AutoResetEvent(true);
TimerCallback callback = new TimerCallback(MyCallback);
timer = new Timer(callback, autoEvent, new TimeSpan(0), new Timespan(5));

Dynamic Threading with Start, Pause and Stop event handling

I have created sample application and implemented threading. basically aim to craete this application is i would like to
If any process(s) are runnig then User Interface should Notify
[DONE]
Handle dynamically created thread with ProgressBar [DONE]
Provide addition functionality to Start, Pause and Stop thread from
available progress list. [NEED YOUR HELP]
Note:- I don't have much knowledge about Threading and Delegates, so please let me know best solution for existing code.
Files and Controls are used:-
Basically three files are used in this demo application
ProgressForm.cs (Window Form)
which conatains Button for creating new progress and Container whic will hold all the created progressbars
ProgressClass.cs
Which contains Dynamic Threading and Delegates to Notify UI without locking or hanging user interface
ProgressControl.cs (User Control)
Which contains
Progressbar (to display process done)
Precent Label (display percentage of completed progress)
Start/Pause button (for play/pause a thread)
Stop button (stop running thread and remove progress from list)
StartTime Label (display process started time)
EndTime label (display time of process completed)
MaxValue Lable (generate random number between 25 to 100)
CODE SNIPPET:-
1. ProgressForm .cs
public partial class ProgressForm : Form
{
Random randomMaxValue = new Random();
public ProgressForm()
{
InitializeComponent();
}
private void btnStart_Click(object sender, EventArgs e)
{
ProgressClass m_clsProcess;
ProgressControl progress = new ProgressControl();
progress.StartedAt = DateTime.Now;
progress.MinValue = 0;
progress.CurrentValue = 0;
progress.MaxValue = randomMaxValue.Next(25, 100);
AddControl(progress);
m_clsProcess = new ProgressClass(progress, this, new ProgressClass.NotifyProgress(DelegateProgress));
m_clsProcess.Start();
}
private void DelegateProgress(int CurrentValue, ProgressControl Progress)
{
ProgressBar p = (ProgressBar)Progress.Controls.Find("pgbPercent", false)[0];
p.Minimum = Progress.MinValue;
p.Value = CurrentValue;
p.Maximum = Progress.MaxValue;
Label percent = (Label)Progress.Controls.Find("lblPercent", false)[0];
percent.Text = string.Format("{0:#00} %", Convert.ToInt16((CurrentValue * 100) / Progress.MaxValue));
Label start = (Label)Progress.Controls.Find("lblStart", false)[0];
start.Text = string.Format("{0:HH:mm:ss}", Progress.StartedAt);
if (CurrentValue == Progress.MaxValue)
{
Label complete = (Label)Progress.Controls.Find("lblComplete", false)[0];
complete.Text = string.Format("{0:HH:mm:ss}", DateTime.Now);
Progress.Status = ProgressControl.ProgressStatus.Completed;
}
Label max = (Label)Progress.Controls.Find("lblMaxValue", false)[0];
max.Text = string.Format("{0:#00}", Progress.MaxValue);
Button btnstartstop = (Button)Progress.Controls.Find("btnStartStop", false)[0];
btnstartstop.Click += new EventHandler(ProgressStartStop);
}
private void AddControl(Control ctl)
{
tableLayoutPnl.RowCount += 1;
tableLayoutPnl.RowStyles.Add(new RowStyle());
ctl.Dock = DockStyle.Fill;
tableLayoutPnl.Controls.Add(ctl, 0, tableLayoutPnl.RowCount - 1);
}
void ProgressStartStop(object sender, EventArgs e)
{
Button btn = sender as Button;
//
//Here i would like to write a code for START / PAUSE thread and update Image acording too.
//
}
}
2. ProgressControl.cs
public partial class ProgressControl : UserControl
{
public enum ProgressStatus
{
Initialize,
Running,
Paused,
Completed
}
public DateTime StartedAt { get; set; }
public DateTime CompletedAt { get; set; }
public int MinValue { get; set; }
public int CurrentValue { get; set; }
public int MaxValue { get; set; }
public ProgressStatus Status { get; set; }
public ProgressControl()
{
InitializeComponent();
this.Status = ProgressStatus.Initialize;
}
}
3. ProgressClass.cs
public class ProgressClass
{
private int ThreadWaitTime = 100;
private ProgressControl m_progress;
private NotifyProgress m_clsNotifyDelegate;
private System.Threading.Thread m_clsThread;
private System.ComponentModel.ISynchronizeInvoke m_clsSynchronizingObject;
public delegate void NotifyProgress(int PercentComplete, ProgressControl Progress);
public ProgressClass(ProgressControl Progress, System.ComponentModel.ISynchronizeInvoke SynchronizingObject, NotifyProgress NotifyDelegate)
{
m_progress = Progress;
m_clsSynchronizingObject = SynchronizingObject;
m_clsNotifyDelegate = NotifyDelegate;
}
public void Start()
{
m_clsThread = new System.Threading.Thread(DoProcess);
m_clsThread.Name = "Background Thread";
m_clsThread.IsBackground = true;
m_progress.Status = ProgressControl.ProgressStatus.Running;
m_clsThread.Start();
}
private void DoProcess()
{
for (int i = m_progress.MinValue; i <= m_progress.MaxValue; i++)
{
NotifyUI(i);
Thread.Sleep(ThreadWaitTime);
}
}
private void NotifyUI(int Value)
{
object[] args = new object[2];
args[0] = Value;
args[1] = m_progress;
m_clsSynchronizingObject.Invoke(m_clsNotifyDelegate, args);
}
}
I am not asking for write whole code instead of provide hint.
I would like to start/pause relevent thread from list, os what should i do for that?
I would like hind in following function:
void ProgressStartStop(object sender, EventArgs e)
{
Button btn = sender as Button;
//Here i would like to write a code for START / PAUSE thread and update Image acording too.
}
UPDATED:
You will want to use a ManualResetEvent or ManualResetEventSlim to create the pause and resume behavior in the thread. The idea is to check the state of the event in the worker thread at safe points. This is done via the WaitOne or Wait methods. If the event is signaled then the calls will return immediately allowing the thread to proceed. If the event is unsignaled then the calls block until the event is signaled via the Set method. So to pause the thread you would call Reset to unsignal the event and to resume the thread you would call Set.
Just remember to place calls to WaitOne or Wait at safe points in the instruction sequence of the worker thread. In other words, do not call these methods inside a lock or something like that. At the beginning or end of a loop is often a good start.
Also, it looks like you use the Invoke method for updating the UI. That is all fine and good, but for simply updating the UI with progress information there is a better option. It is better to publish the progress information to a shared data structure and then have the UI thread pick it up via a timer. For those that monitor my answers I harp about this a lot, I know. But, this strategy has a lot of advantages.
It breaks the tight coupling between the UI and worker threads that Invoke imposes.
It puts the responsibility of updating the UI thread on the UI thread where it should belong anyway.
The UI thread gets to dictate when and how often the update should take place.
There is no risk of the UI message pump being overrun as would be the case with the marshaling techniques initiated by the worker thread.
The worker thread does not have to wait for an acknowledgement that the update was performed before proceeding with its next steps (ie. you get more throughput on both the UI and worker threads).
It avoids the subtle race conditions that can occur when trying to gracefully end the worker thread.
It is more efficient since Invoke is an expensive operation.
Update:
Here is the general idea regarding the changes that could be made to ProgressStartStop.
private Dictionary<int, ThreadInfo> threads = new Dictionary<int, ThreadInfo>();
void ProgressStartStop(object sender, EventArgs e)
{
Button button = sender as Button;
int index = GetThreadIndexFromButton(button);
if (!threads.ContainsKey(index))
{
// The thread has not been started yet so do it now.
var thread = new Thread(RunThread);
thread.Start();
var mres = new ManualResetEventSlim(true);
var info = new ThreadInfo { Thread = thread, ProceedSignal = mres };
threads.Add(index, info);
// Change the button image here.
}
else
{
ThreadInfo info = threads[index];
if (info.ProceedSignal.Wait(0))
{
// The event is signaled which means the thread is running. Pause it.
info.ProceedSignal.Reset();
// Change the button image here.
}
else
{
// The event is unsignaled which means the thread is paused. Resume it.
info.ProceedSignal.Set();
// Change the button image here.
}
}
}
private class ThreadInfo
{
Thread Thread { get; set; }
ManualResetEventSlim ProceedSignal { get; set; }
}
It is generally considered bad practice to Suspend threads (though it is possible). The right way to pause and terminate threads is through the cooperation with the job that the thread is doing. The job should check a variable in a loop, and pause or exit accordingly. The controlling program can set that variable, and if you need feedback the background thread can call a notification method before exiting or sleeping.

Resources