簡體   English   中英

如何在C#中使用Timer

[英]how to use Timer in C#

我正在使用system.Timers.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

你不能將額外的參數傳遞給事件處理程序回調,因為你不是那個調用它的人 - 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");
}

現在,Elapsed處理程序是(timerSender, timerEvent) => lambda動作,它關閉receiver變量,並在每次觸發lambda時使用extra參數手動調用send

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

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屬性將事件編組到正確的線程更容易:

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;
}

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

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

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");
}
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)
    {

    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM