Alternative to stopwatch?
Asked Answered
T

4

6

I am working on a very simple stopwatch using WPF but using the System.Diagnostics stopwatch was very slow and not reliable at all, compared to my system clock every 1 second from my application was 3 seconds on an actual clock.

I did some search about stopwatch being slow, found lots of results but no solution to it, so I decided to come up with my own counter.

Here is an sample of what I came up with:

System.Windows.Threading.DispatcherTimer _update;
DateTime _started;
bool isRunning = false;

The update thread:

_update = new System.Windows.Threading.DispatcherTimer(new TimeSpan(0, 0, 0, 0, 1), System.Windows.Threading.DispatcherPriority.Normal, delegate
{
    if (isRunning)
        iTimer.Content = new DateTime((DateTime.Now - _started).Ticks).ToString("HH:mm:ss");
}, this.Dispatcher);

I have 2 buttons, bToggle which is resposible for starting, stopping and resuming it and another button called bReset.

private void bReset_Click(object sender, RoutedEventArgs e)
{
    isRunning = false;
    iTimer.Content = "00:00:00";
    bToggle.Content = "Start";
}

private void bToggle_Click(object sender, RoutedEventArgs e)
{
    if ((string)bToggle.Content == "Start")
    {
        isRunning = true;
        _started = DateTime.Now;
        bToggle.Content = "Stop";
    }
    else if ((string)bToggle.Content == "Resume")
    {
        isRunning = true;
        bToggle.Content = "Stop";
    }
    else
    {
        isRunning = false;
        bToggle.Content = "Resume";
    }
}

It works fine to start and reset but since I am using the actual time if I stop and resume, it will jump the seconds until the actual time.

How could I solve this problem or is there an alternative to stopwatch that actually have a good accuracy on the current time ?

Toed answered 4/5, 2012 at 10:47 Comment(13)
What were you using StopWatch for?His
For a stopwatcher ? To put it simple it counts from 0 until u stop or reset.Toed
It just sounds like you were trying to use it as a timer.His
Something like this sport-impianti.com/wp-content/gallery/atletica/4103.jpg but as a desktop application. Either way if u look at the above code, its a fully working on, I just need to figure out how to do the stop/resume function or if there is a better way to control it.Toed
StopWatch has issues on some hardware(for example constant offsets between cores), but I never heard of a multiplicative error. Can you post your StopWatch code?Geesey
Now you are being silly. The StopWatch class is intended to count time differences. Timers are intended to execute pieces of code on a schedule. It is not clear what you are trying to do.His
CodeInChaos I would but I already got ride of it and moved to the above one after several tries and no useful results from searchs.Toed
Oded LOL man, I am doing a en.wikipedia.org/wiki/Stopwatch this my sound confusing as I was trying to use the StopWatch class to make a StopWatch, but thats what I am doing a Stopwatch for desktop that can be stopped and resumed.Toed
Again, it sounds like you need a timer. Timers can be stopped and resumed.His
I wrote a stopwatch/clock/countdown timer recently in WPF to be used at the back of a church to help the speaker know how long they've been preaching. You're welcome to the code if you want it.Transubstantiate
@His that's why I was looking for an Alternative or solution to my current code but the Timers class hangs my UI.Toed
@Toed - There are several different timer classes. You need to use the right one and your UI will not hang.His
@Guapo: To choose the right timer, you could maybe take a look into this article.Floris
S
2

You need to intruduce an additional variable TimeSpan accumulatedTime in which you save the elapsed interval whenever someone clicks stop.

And:

iTimer.Content = (new DateTime((DateTime.Now - _started).Ticks) + accumulatedTime).ToString("HH:mm:ss");
Sheets answered 4/5, 2012 at 10:56 Comment(1)
very appreciated, I have resolved it with the follow: new DateTime((DateTime.Now.Subtract(accumulatedTime) - _tempo).Ticks).ToString("HH:mm:ss");Toed
I
1

Use System.Timers.Timer

You can start and stop this, and set a counter in the timers tick event.

This is a simple example:

public partial class MainWindow : Window
{
    private Timer _timer;
    private int _time;

    public MainWindow()
    {
        InitializeComponent();

        _time = 0;

        _timer = new Timer(1000);
        _timer.Elapsed += new ElapsedEventHandler(_timer_Elapsed);
    }

    void _timer_Elapsed(object sender, ElapsedEventArgs e)
    {

        Dispatcher.Invoke(new Action(() =>
                                         {
                                             _time++;
                                             tbTime.Text = _time.ToString();
                                         }));

    }

    private void btnStartStop_Click(object sender, RoutedEventArgs e)
    {
        if (_timer.Enabled)
        {
            _timer.Stop();
        }
        else
        {
            _timer.Start();
        }
    }
}

Xaml:

<Grid>
    <StackPanel>
        <Button Name="btnStartStop" Content="start/stop timer" Click="btnStartStop_Click" />
        <TextBlock Name="tbTime" Text="00:00" />
    </StackPanel>
</Grid>
Ite answered 4/5, 2012 at 11:2 Comment(3)
the fact I am using a thread is so it doesn't hang my application UIToed
this dosn't lock your UI, but if you want to be safe put the timer in a backgroundworker and forward the tick event to worker progresschanged eventIte
jrb if you are constantly moving the app window it does.Toed
T
0

I think this line is your problem:

_update = new System.Windows.Threading.DispatcherTimer(new TimeSpan(0, 0, 0, 0, 1), System.Windows.Threading.DispatcherPriority.Normal

It tells WPF that you want your delegate to execute 1000 times per second, and to schedule it at the second-highest priority. That's a higher priority than Render and DataBind, and I think both Render and DataBind are needed to actually display the updated value you put in iTimer.Content.

You should set the DispatcherPriority to Background and use a lower frequency (e.g. 20 ms - humans can't see anything faster than 50 fps, anyway.)

Thetic answered 4/5, 2012 at 11:17 Comment(1)
With the code in my question it updates just fine but using the stopwatch class it was not so that would cut out that line as being the problem in my opinion.Toed
E
0

MiniProfiler

Answering to the topic, as an alternative to the Stopwatch, you may use the MiniProfiler:

You may use the profiler step to get data to analyze, like:

var profiler = MiniProfiler.StartNew("My Profiler Name");
using (profiler.Step("Main Work"))
{
    // Do some work...
}

There's separate UI for the profiler, but you can grab the data in the debug mode or write it to the text file.

Links:

Ealing answered 13/9, 2024 at 9:19 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.