2010-08-30 43 views
3

在我的應用程序中有時會需要手動調用我的計時器。告訴計時器對象異步調用其「Elapsed」事件

我已經試過如下:

int originalInterval = t.Interval; 
t.Interval = 0; 
t.Interval = originalInterval; 

,但它並不一致。

我已經創建了一個新的計時器,它繼承自System.Timers.Timer,並暴露了一個「Tick」方法 - 但問題在於「Elapsed」事件隨後同步觸發。

當我使用新線程實現「Tick」時,結果再次不一致。

有沒有更好的實現方法?

+0

結果不一致的方式是什麼? – 2010-08-30 07:46:32

+0

1.由於使用了Thread.Start而不是ThreadPool.Queue(我不想使用......太難看),因此線程被關閉了。 2.當用戶多次調用「Tick」(在方法停止) - 我希望它等待第一個電話完成每一次,並調用它只有然後 – Fliskov 2010-08-30 07:51:32

回答

4

我曾經有過同樣的問題,所以我用的AutoResetEvent知道如果經過成功調用:

/// <summary> 
/// Tickable timer, allows you to manually raise a 'Tick' (asynchronously, of course) 
/// </summary> 
public class TickableTimer : System.Timers.Timer 
{ 
    public new event ElapsedEventHandler Elapsed; 

    private System.Threading.AutoResetEvent m_autoResetEvent = new System.Threading.AutoResetEvent(true); 

    public TickableTimer() 
     : this(100) 
    { 
    } 

    public TickableTimer(double interval) 
     : base(interval) 
    { 
     base.Elapsed += new ElapsedEventHandler(TickableTimer_Elapsed); 
    } 

    public void Tick() 
    { 
     new System.Threading.Thread(delegate(object sender) 
     { 
      Dictionary<string, object> args = new Dictionary<string, object> 
      { 
       {"signalTime", DateTime.Now}, 
      }; 
      TickableTimer_Elapsed(this, Mock.Create<ElapsedEventArgs>(args)); 
     }).Start(); 
     this.m_autoResetEvent.WaitOne(); 
    } 

    void TickableTimer_Elapsed(object sender, ElapsedEventArgs e) 
    { 
     m_autoResetEvent.Set(); 
     if (this.Elapsed != null) 
      this.Elapsed(sender, e); 
    } 
} 
+0

偉大的傢伙!做得很好! (使用'Mock'很棒!) – Fliskov 2010-08-30 07:39:17

+0

我使用'Moke',因爲它的構造函數是私有的 – Nissim 2010-08-30 07:40:05

+0

哪個命名空間包含Mock? – 2015-12-26 09:22:00

0

通常情況下,你不應該需要手動觸發一個計時器 - 你永遠可以運行事件本身在一個新的線程中。總的來說,這基本上就是計時器的功能,因爲您想手動觸發它,所以不需要定時器(用於手動調用)。

您沒有詳細說明「不一致」的含義。下面應正常工作:

Thread thread = new Thread(myDelegate); 
thread.Start(); 

當然,myDelegate可以在情況下,你需要傳遞參數拉姆達:

Thread thread = new Thread(() => myMethod(param1, param2)); 
thread.Start(); 
+0

我試過了 - 但結果總是不一致......尤其是當用戶多次調用「Tick」時 – Fliskov 2010-08-30 07:38:55

+0

@Fliskov:說「它不一致」沒有用處現在比在你的問題。任何細節? – Timwi 2010-08-30 07:42:42

+0

查看對@Fredreck的評論 – Nissim 2010-08-30 08:03:38

3

這種感覺就像你應該看看你的設計了一下。通常我會盡量避免讓事件處理程序方法包含正在完成的實際工作,但我寧願讓它只是一個觸發器,並調用其他執行該工作的方法。這樣,你可以從其他地方以及調用其他方法:

private void Timer_Tick(object sender, EventArgs e) 
{ 
    new Thread(MethodThatDoesTheWork).Start(); 
} 

private void MethodThatDoesTheWork() 
{ 
    // actual work goes here 
} 

現在,你可以從類中其他地方調用MethodThatDoesTheWork(同步或異步使用一個單獨的線程)。

另外,如果MethodThatDoesTheWork始終是一個異步調用,您可以生成的線程方法,而不是內部:

private void MethodThatDoesTheWork() 
{ 
    new Thread(() => 
    { 
     // work code goes here 
    }).Start(); 
} 

在這些樣品中我有手動創建的線程。您可以使用該方法,即ThreadPool,Task或任何其他方法來異步調用代碼,無論哪種方法最適合您的情況。

+0

正如我的問題所暗示的 - 使用Thread.Start並未解決問題 – Fliskov 2010-08-30 07:43:34

+0

@Fliskov:您的問題指出,在單獨的線程上調用「Tick」事件並不能解決問題。我的建議是避免調用它。也許你可以詳細說明你的代碼在問題中的實際作用(這將使得提供有用的答案變得更容易)? – 2010-08-30 07:45:56