【问题标题】:Alternative to stopwatch?秒表的替代品?
【发布时间】:2012-05-13 21:51:12
【问题描述】:

我正在使用 WPF 开发一个非常简单的秒表,但使用 System.Diagnostics 秒表非常慢而且根本不可靠,相比之下,我的应用程序每 1 秒的系统时钟在实际时钟上是 3 秒。

我做了一些关于秒表慢的搜索,找到了很多结果但没有解决办法,所以我决定想出自己的计数器。

这是我想出的一个示例:

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

更新线程:

_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);

我有 2 个按钮,bToggle 负责启动、停止和恢复它,另一个按钮称为 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";
    }
}

它可以正常启动和重置,但由于我使用的是实际时间,如果我停止和恢复,它会跳秒直到实际时间。

我该如何解决这个问题,或者是否有替代秒表的替代品,实际上对当前时间有很好的准确性?

【问题讨论】:

  • 你用StopWatch做什么?
  • 对于秒表?简单地说,它从 0 开始计数,直到你停止或重置。
  • 听起来你正试图将它用作计时器。
  • 类似 sport-impianti.com/wp-content/gallery/atletica/4103.jpg 的东西,但作为桌面应用程序。无论哪种方式,如果您查看上面的代码,它已经完全正常工作,我只需要弄清楚如何执行停止/恢复功能,或者是否有更好的方法来控制它。
  • StopWatch 在某些硬件上存在问题(例如内核之间的恒定偏移),但我从未听说过乘法错误。你能发布你的StopWatch 代码吗?

标签: c# wpf stopwatch


【解决方案1】:

您需要引入一个额外的变量TimeSpan accumulatedTime,您可以在其中保存每当有人点击停止时经过的时间间隔。

还有:

iTimer.Content = (new DateTime((DateTime.Now - _started).Ticks) + accumulatedTime).ToString("HH:mm:ss");

【讨论】:

  • 非常感谢,我已经通过以下方式解决了它:new DateTime((DateTime.Now.Subtract(accumulatedTime) - _tempo).Ticks).ToString("HH:mm:ss");
【解决方案2】:

使用System.Timers.Timer

您可以启动和停止它,并在计时器滴答事件中设置一个计数器。

这是一个简单的例子:

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>

【讨论】:

  • 我使用线程的事实是它不会挂起我的应用程序 UI
  • 这不会锁定您的 UI,但如果您想安全起见,请将计时器放在后台工作人员中并将滴答事件转发给工作人员进度更改事件
  • jrb 如果你经常移动它的应用程序窗口。
【解决方案3】:

我认为这条线是你的问题:

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

它告诉 WPF 您希望您的代理每秒执行 1000 次,并将其安排在第二高的优先级。这比RenderDataBind 具有更高的优先级,我认为需要Render 和DataBind 才能实际显示您在iTimer.Content 中输入的更新值。

您应该将 DispatcherPriority 设置为 Background 并使用较低的频率(例如 20 毫秒 - 无论如何,人类看不到任何快于 50 fps 的东西。)

【讨论】:

  • 使用我的问题中的代码,它更新得很好,但使用秒表类,在我看来,这并不是问题所在。
猜你喜欢
  • 1970-01-01
  • 2012-11-02
  • 1970-01-01
  • 1970-01-01
  • 2023-03-16
  • 2015-05-25
  • 1970-01-01
  • 2020-02-17
  • 1970-01-01
相关资源
最近更新 更多