2012-06-19 30 views
15

我正在使用system.Timers.Timer創建一個計時器。如何在C中使用Timer#

public System.Timers.Timer timer = new System.Timers.Timer(200); 
private void btnAutoSend_Click(object sender, EventArgs e) 
{ 
    timer.Enabled = true; 
    timer.Elapsed += new System.Timers.ElapsedEventHandler(send); 
    timer.AutoReset = true; 
} 

public void send(object source, System.Timers.ElapsedEventArgs e) 
{ 
    this.rtbMsg.AppendText("psyche-->" + receiver + ": hello\n"); 
} 

在發送功能的接收是我需要的時候使用該函數來設置的參數,但是當我添加參數的發送功能,如:

public void send(object source, System.Timers.ElapsedEventArgs e,string receiver) 

然後拋出一個錯誤。在我檢查了MSDN之後,它說ElapsedEventArgs只適用於這些不會產生數據的函數。

我該如何解決這個問題?我的程序不是windows.Form,所以我不能使用System.Windows.Forms.Timer

+0

好了,你可以使用'System.Windows.Forms.Timer'如果你添加到庫中的引用。 – annonymously

+0

相關[如何將sender參數傳遞給system.timers.timer](http://stackoverflow.com/questions/6368399/how-to-pass-the-the-sender-parameter-to-the-system -timers-timer) – Damith

+0

你不應該在任何UI組件中使用System.Windows.Timer(例如rtbMsg.AppendText可能訪問某種類型的Windows控件),System.Timer.Elapsed在非UI線程上被調用並且會導致在大多數情況下是例外。如果你不是WinForms並且是WPF,那麼你會想要使用DispatchTimer。如果你能澄清你收到的錯誤,有人可能會提供更準確的建議。 –

回答

19

您不能將額外的參數傳遞給事件處理函數回調函數,因爲您不是那個調用它的函數 - Timer是;這是整點;-)

但是,你可以輕鬆地完成與結束具有同等效力:

private void btnAutoSend_Click(object sender, EventArgs e) 
{ 
    timer.Elapsed += (timerSender, timerEvent) => send(timerSender, timerEvent, receiver); 
    timer.AutoReset = true; 
    timer.Enabled = true; 
} 

public void send(object source, System.Timers.ElapsedEventArgs e, string receiver) 
{ 
    this.rtbMsg.AppendText("psyche-->" + receiver + ": hello\n"); 
} 

現在經過的處理程序是(timerSender, timerEvent) =>拉姆達行動,其封閉在receiver變量,並調用send每當lambda被觸發時手動使用額外的參數。

在您的具體情況下,您根本不需要發件人或參數,因此無需轉發它們。代碼變爲:

private void btnAutoSend_Click(object sender, EventArgs e) 
{ 
    timer.Elapsed += (s_, e_) => OnTimerElapsed(receiver); 
    timer.AutoReset = true; 
    timer.Enabled = true; 
} 

private void OnTimerElapsed(string receiver) 
{ 
    this.rtbMsg.AppendText("psyche-->" + receiver + ": hello\n"); 
} 

如果您想知道所有這些開銷,它是非常小的。 Lambdas只是語法糖,並且是幕後的普通函數(爲事件提供了一些自動委託包裝)。閉包是使用編譯器生成的類來實現的,但除非您真的擁有它們,否則不會注意到任何代碼膨脹。

正如評論中指出的那樣,您似乎在訪問OnTimerElapsed代碼中的UI元素 - 因爲您沒有使用Windows窗體計時器,所以很有可能會因爲這樣做而收到異常代碼將運行在定時器碰巧運行時的任何線程上 - 並且Windows 中的UI控件必須從創建它們的線程訪問

你可以更動this.Invoke手動修復它,但它更容易有計時器馬歇爾通過SynchronizingObject property事件爲您正確的線程:

private void btnAutoSend_Click(object sender, EventArgs e) 
{ 
    timer.SynchronizingObject = this; // Assumes `this` implements ISynchronizeInvoke 
    timer.Elapsed += (s_, e_) => OnTimerElapsed(receiver); 
    timer.AutoReset = true; 
    timer.Enabled = true; 
} 

最後,另一個提示評論,這裏有另一種方式可以存儲對封閉的引用,以便您可以稍後取消訂閱事件:

private void btnAutoSend_Click(object sender, EventArgs e) 
{ 
    timer.SynchronizingObject = this; // Assumes `this` implements ISynchronizeInvoke 
    ElapsedEventHandler onElapsed; 
    onElapsed = (s_, e_) => { 
     timer.Elapsed -= onElapsed; // Clean up after firing 
     OnTimerElapsed(receiver); 
    }; 
    timer.Elapsed += onElapsed; 
    timer.AutoReset = true; 
    timer.Enabled = true; 
} 
+0

爲什麼在設置自動復位和回叫之前啓動定時器? timer.Enabled = true應該是你做的最後一件事 – nbrooks

+0

@nbrooks:好點,我只是複製OP的代碼。我將在 – Cameron

+0

中編輯@nbrooks與timer.Start()相同嗎? – Damith

3

您不能將額外的參數傳遞給這樣的事件處理程序。

將您的值存儲在對象級別變量中,以便可以在事件處理程序中訪問它。

private string receiver; 

public System.Timers.Timer timer = new System.Timers.Timer(200); 
private void btnAutoSend_Click(object sender, EventArgs e) 
{ 
    timer.Enabled = true; 
    receiver = 'your val'; 
    timer.Elapsed += new System.Timers.ElapsedEventHandler(send); 
    timer.AutoReset = true; 
} 

public void send(object source, System.Timers.ElapsedEventArgs e) 
{ 
    this.rtbMsg.AppendText("psyche-->" + receiver + ": hello\n"); 
} 
2
public partial class Form2 : Form 
{ 
    Timer timer = new Timer(); 
    public Form2() 
    { 
     InitializeComponent(); 
     timer.Tick += new EventHandler(timer_Tick); // Every time timer ticks, timer_Tick will be called 
     timer.Interval = (10) * (1000);    // Timer will tick every 10 seconds 
     timer.Start();        // Start the timer 
    } 
    void timer_Tick(object sender, EventArgs e) 
    { 
     //MessageBox.Show("Tick");     // Alert the user 
     var time = DateTime.Now; 
     label1.Text = $"{time.Hour} : {time.Minute} : {time.Seconds} : {time.Milliseconds}"; 
    } 
    private void Form2_Load(object sender, EventArgs e) 
    { 

    } 
}