2010-08-02 29 views
15

Tôi đang sử dụng Bộ hẹn giờ để chạy một sự kiện định kỳ trong một khoảng thời gian khá dài (2 phút). Điều này làm việc tốt. Tuy nhiên, tôi muốn sự kiện này kích hoạt ngay lập tức khi bộ hẹn giờ được tạo (thay vì đợi 2 phút).Làm cho hệ thống .Tây lửa.Timers.Timer cháy ngay lập tức

Lưu ý rằng tôi không thể làm điều này chỉ bằng cách gọi phương thức, vì phải mất một thời gian để chạy và sẽ chặn ứng dụng. Tôi cần bộ đếm thời gian để kích hoạt như bình thường và chạy sự kiện trong một chủ đề riêng biệt.

Cách tốt nhất tôi có thể nghĩ để làm điều này vào lúc này là subclassing bộ đếm thời gian và tạo ra một phương pháp TriggerManually mà có thể làm một cái gì đó như thế này:

  • Bật tự động reset tắt
  • Đặt khoảng thời gian để 1ms
  • kích hoạt tính năng hẹn giờ

Điều này sẽ kích hoạt các sự kiện trôi qua ngay lập tức, và tôi có thể đặt tất cả các thiết lập trở lại bình thường.

Dường như có một chút bùng binh. Có cách nào tốt hơn để làm điều đó không?

Trả lời

4

Bạn có thể sử dụng System.Threading.Timer thay thế không? Nó có một hàm tạo cho phép bạn chọn khoảng thời gian cũng như độ trễ (có thể được đặt thành 0 để bắt đầu ngay). http://msdn.microsoft.com/en-us/library/2x96zfy7.aspx

+0

@Mitch - chỉ cần chứng minh rằng bạn đang Mặc dù có con người của đại diện điên rồ của bạn :) – Gishu

+0

Yep, công trình này. System.Threading.Timer là một chút khó khăn hơn để sử dụng, nhưng nó làm những gì tôi cần. Cảm ơn! – Nathan

+2

Được cảnh báo rằng một ngoại lệ chưa được xử lý trong cuộc gọi lại của «System.Threading.Timer' [sẽ làm hỏng ứng dụng của bạn] (http://stackoverflow.com/questions/1718598/throwing-exceptions-in-callback-method-for-timers). –

12

Bạn không thể gọi trình xử lý sự kiện của mình cho sự kiện đã trôi qua theo cách thủ công?

Thậm chí nếu bạn đang mong đợi nó thực hiện trên một chuỗi chủ đề chuỗi, bạn có thể gọi nó.

class Blah 
{ 
    private Timer mTimer; 

    public Blah() 
    { 
     mTimer = new Timer(120000); 

     ElapsedEventHandler handler = new ElapsedEventHandler(Timer_Elapsed); 
     mTimer.Elapsed += handler; 
     mTimer.Enabled = true; 

     //Manually execute the event handler on a threadpool thread. 
     handler.BeginInvoke(this, null, new AsyncCallback(Timer_ElapsedCallback), handler); 
    } 

    private static void Timer_Elapsed(object source, ElapsedEventArgs e) 
    { 
     //Do stuff... 
    } 

    private void Timer_ElapsedCallback(IAsyncResult result) 
    { 
     ElapsedEventHandler handler = result.AsyncState as ElapsedEventHandler; 
     if (handler != null) 
     { 
      handler.EndInvoke(result); 
     } 
    } 
} 
5

Tôi thích câu trả lời Rob Cooke, vì vậy tôi đã xây dựng một lớp học nhỏ EagerTimer rằng lớp con System.Timers.Timer và thêm chức năng này. (Với gợi ý từ thesearticles)

Tôi biết tôi có thể sử dụng System.Threading.Timer thay vào đó, nhưng điều này rất đơn giản và hoạt động tốt trong ứng dụng của tôi.

EagerTimer

/// <summary> 
// EagerTimer is a simple wrapper around System.Timers.Timer that 
// provides "set up and immediately execute" functionality by adding a 
// new AutoStart property, and also provides the ability to manually 
// raise the Elapsed event with RaiseElapsed. 
/// </summary> 
public class EagerTimer : Timer 
{ 
    public EagerTimer() 
     : base() { } 

    public EagerTimer(double interval) 
     : base(interval) { } 

    // Need to hide this so we can use Elapsed.Invoke below 
    // (otherwise the compiler complains) 
    private event ElapsedEventHandler _elapsedHandler; 
    public new event ElapsedEventHandler Elapsed 
    { 
     add { _elapsedHandler += value; base.Elapsed += value; } 
     remove { _elapsedHandler -= value; base.Elapsed -= value; } 
    } 

    public new void Start() 
    { 
     // If AutoStart is enabled, we need to invoke the timer event manually 
     if (AutoStart) 
     { 
      this._elapsedHandler.BeginInvoke(this, null, new AsyncCallback(AutoStartCallback), _elapsedHandler); // fire immediately 
     } 

     // Proceed as normal 
     base.Start(); 
    } 

    private void AutoStartCallback(IAsyncResult result) 
    { 
     ElapsedEventHandler handler = result.AsyncState as ElapsedEventHandler; 
     if (handler != null) handler.EndInvoke(result); 
    } 

    // Summary: 
    //  Gets or sets a value indicating whether the EagerTimer should raise 
    //  the System.Timers.Timer.Elapsed event immediately when Start() is called, 
    //  or only after the first time it elapses. If AutoStart is false, EagerTimer behaves 
    //  identically to System.Timers.Timer. 
    // 
    // Returns: 
    //  true if the EagerTimer should raise the System.Timers.Timer.Elapsed 
    //  event immediately when Start() is called; false if it should raise the System.Timers.Timer.Elapsed 
    //  event only after the first time the interval elapses. The default is true. 
    [Category("Behavior")] 
    [DefaultValue(true)] 
    [TimersDescription("TimerAutoStart")] 
    public bool AutoStart { get; set; } 

    /// <summary> 
    /// Manually raises the Elapsed event of the System.Timers.Timer. 
    /// </summary> 
    public void RaiseElapsed() 
    { 
     if (_elapsedHandler != null) 
      _elapsedHandler(this, null); 
    } 
} 

Unit Tests

[TestClass] 
public class Objects_EagerTimer_Tests 
{ 
    private const int TimerInterval = 10; // ms 

    private List<DateTime> _timerFires = new List<DateTime>(); 
    private DateTime _testStart; 

    [TestInitialize] 
    public void TestSetup() 
    { 
     _timerFires.Clear(); 
     _testStart = DateTime.Now; 
    } 

    [TestMethod] 
    public void Objects_EagerTimer_WithAutoStartDisabled() 
    { 
     // EagerTimer should behave as a normal System.Timers.Timer object 
     var timer = new EagerTimer(TimerInterval); 
     timer.AutoReset = false; 
     timer.Elapsed += timerElapsed; 
     timer.Start(); 

     // Wait (not enough time for first interval) 
     Thread.Sleep(5); 
     Assert.IsFalse(_timerFires.Any()); 

     // Wait a little longer 
     Thread.Sleep(TimerInterval); 
     Assert.AreEqual(1, _timerFires.Count); 
    } 

    [TestMethod] 
    public void Objects_EagerTimer_WithAutoStartEnabled() 
    { 
     // EagerTimer should fire immediately on Start() 
     var timer = new EagerTimer(TimerInterval); 
     timer.AutoReset = false; 
     timer.AutoStart = true; 
     timer.Elapsed += timerElapsed; 
     timer.Start(); 

     // Wait (not enough time for first interval) 
     Thread.Sleep(5); 
     Assert.IsTrue(_timerFires.Any()); 

     // Wait a little longer, now it will have fired twice 
     Thread.Sleep(TimerInterval); 
     Assert.AreEqual(2, _timerFires.Count); 
    } 

    [TestMethod] 
    public void Objects_EagerTimer_WhenRaisingManually() 
    { 
     // EagerTimer should fire immediately on Start() 
     var timer = new EagerTimer(TimerInterval); 
     timer.AutoReset = false; 
     timer.AutoStart = false; 
     timer.Elapsed += timerElapsed; 

     Assert.IsFalse(_timerFires.Any()); 
     timer.RaiseElapsed(); 
     Assert.IsTrue(_timerFires.Any()); 
    } 

    private void timerElapsed(object sender, ElapsedEventArgs e) { 
     _timerFires.Add(DateTime.Now); 
    } 
} 
Các vấn đề liên quan