4

我需要一个计时器类,它应该提供启动/停止/启用/禁用的功能,并且应该是非 UI。

我看到 2 个选项

  1. DispatcherTimer -> 具有除在 UI 线程上执行之外的所有功能

  2. ThreadPoolTimer -> 无法控制周期性计时器。

我正在考虑在线程池计时器上创建包装器,但似乎非常复杂,因为对它没有/有限的控制。

如何为所述场景设计计时器类。(我需要类似于 System.Threading.Timer 的东西)。

4

2 回答 2

4

由于 UI 在 Metro 应用程序中的响应速度应该非常快 - 运行 DispatcherTimer 并在您希望在后台线程上运行的东西上调用 Task.Run() 可能就足够了。

如果这对您不起作用 - 看看是否有效。它应该具有与 DispatcherTimer 类似的 API,但在不同的线程上运行。并不是说它一直在等待 Interval 集的持续时间,所以计时器会迟到。它也不完全是线程安全的,我只玩了 10 分钟,所以它可能并不总是有效,但由于它是开源的 - 你可以修改它以适应你的账单。

public class BackgroundTimer
{
    private AutoResetEvent _stopRequestEvent;
    private AutoResetEvent _stoppedEvent;

    #region Interval
    private TimeSpan _interval;
    public TimeSpan Interval
    {
        get
        {
            return _interval;
        }
        set
        {
            if (IsEnabled)
            {
                Stop();
                _interval = value;
                Start();
            }
            else
            {
                _interval = value;
            }
        }
    }
    #endregion

    public event EventHandler<object> Tick;

    #region IsEnabled
    private bool _isEnabled;
    public bool IsEnabled
    {
        get
        {
            return _isEnabled;
        }
        set
        {
            if (_isEnabled == value)
                return;

            if (value)
                Start();
            else
                Stop();
        }
    } 
    #endregion

    public BackgroundTimer()
    {
        _stopRequestEvent = new AutoResetEvent(false);
        _stoppedEvent = new AutoResetEvent(false);
    }

    public void Start()
    {
        if (_isEnabled)
        {
            return;
        }

        _isEnabled = true;
        _stopRequestEvent.Reset();
        Task.Run((Action)Run);
    }

    public void Stop()
    {
        if (!_isEnabled)
        {
            return;
        }

        _isEnabled = false;
        _stopRequestEvent.Set();
        _stoppedEvent.WaitOne();
    }

    private void Run()
    {
        while (_isEnabled)
        {
            _stopRequestEvent.WaitOne(_interval);

            if (_isEnabled &&
                Tick != null)
            {
                Tick(this, null);
            }
        }

        _stoppedEvent.Set();
    }
}
于 2012-05-08T06:41:16.887 回答
0

我能够使用以下代码创建一个时钟:

ThreadPoolTimer Timer1 = ThreadPoolTimer.CreatePeriodicTimer(Timer1_ElapsedHandler, TimeSpan.FromSeconds(1));
clockTick = false;
UpdateLoop();

为此,您需要一个事件处理程序,在我的时钟中,计时器已计时:

public void Timer1_ElapsedHandler(ThreadPoolTimer timer)
{
    clockTick = true;
}

然后更新 GUI(或任何你需要的东西),有一个更新循环:

public async void UpdateLoop()
{
    do
    {
        await Task.Delay(100);
    } while (!clockTick);
    ClockTextBlock.Text = DateTime.Now.ToString();
    clockTick = false;
    UpdateLoop();
}

可能将其包装在一个类中并对其进行一些清理可能会为您提供良好的非 UI 计时器的基础。

于 2012-10-01T23:05:21.007 回答