如何制作在主线程中触发事件的 C# 计时器? [英] How to make a C# timer that fires events in the main thread?

查看:27
本文介绍了如何制作在主线程中触发事件的 C# 计时器?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

长话短说,我需要在 .Net 中有一个精确的计时器 - 以毫秒为单位 - 意思是,如果我告诉它在 10 毫秒过去时触发一个事件,它必须这样做,+-1 毫秒.内置的 .Net Timer 类似乎具有 +-16ms 的精度,这对我的应用程序来说是不可接受的.

Long story short, I need a precise timer in .Net - with prescision in milliseconds - meaning, if I tell it to fire an event when 10ms passes, it must do so, +-1ms. The built-in .Net Timer class has a precision of +-16ms it seems, which is unacceptable for my application.

我发现这篇文章 http://www.codeproject.com/Articles/98346/Microsecond-and-Millisecond-NET-Timer 它提供了一个计时器代码,这正是我需要的(甚至更多 - 以微秒为单位).

I found this article http://www.codeproject.com/Articles/98346/Microsecond-and-Millisecond-NET-Timer which provides a code for a timer that is exactly what I need (even more - that has precision in microseconds).

然而,问题是,OnTimer 等效项似乎在另一个线程中执行.所以,如果我添加一些代码,请说:

However, problem is, the OnTimer equivalent seems to be executed in another thread. So, if I add some code that does, say:

label1.Text = "Hello World";

我会得到一个异常,因此我必须像这样写:

I will get an exception, and thus I will have to actually write it like this:

Invoke( new MethodInvoker(() =>{label1.Text = "Hello World";}));

这是,据我所知,因为 OnTimer 事件是从计时器的线程中触发的 - 时间过去了,直到足够的时间超过间隔,然后触发下一个 OnTimer 事件..Net Timer没有这样的问题——在.Net Timer的OnTimer中,我可以自由修改控件的成员.

This is, from what I understand, because the OnTimer event is fired from the timer's thread - where time is passed until enough has passed to be over the Interval, and then next OnTimer event is fired. The .Net Timer does not have such a problem - in OnTimer of the .Net Timer, I can freely modify controls's members.

问题:我应该更改什么才能让我的计时器在主线程中运行它的 OnTimer 事件?添加调用"是唯一的选择吗?

Question: What should I change so that my timer will run it's OnTimer event in the main thread? Is adding "Invoke" the only choice?

推荐答案

虽然有多种方法可以解决,但我通常更喜欢的一种方法是让计时器捕获 SynchronizationContext.Current 创建时.当在 UI 线程中时,该值将包含当前同步​​上下文,当在 UI 上下文中时,该值可用于执行消息循环中的方法.这适用于 winform、WPF、silverlight 等.所有这些范式都设置了同步上下文.

While there are several ways of going about it, the one that I would generally prefer is to have the timer capture the value of SynchronizationContext.Current when it is created. That value will, when in the UI thread, contain the current synchronization context which can be used to execute methods in the message loop when in a UI context. This will work for winforms, WPF, silverlight, etc. All of those paradigms set a synchronization context.

只要在创建计时器时获取该值,假设它是在 UI 线程中创建的.如果您希望有一个可选的构造函数/属性来设置值,以便即使计时器不是在 UI 线程中创建的情况下也可以使用它,您也可以使用它,尽管在大多数情况下不需要这样做.

Just grab that value when the timer is created, assuming it's created in the UI thread. If you want have an optional constructor/property to set the value so that you can use it even if the timer isn't created in the UI thread you can, although that shouldn't be needed most of the time.

然后只需使用该上下文的 Send 方法来触发事件:

Then just use the Send method of that context to fire the event:

public class Timer
{
    private SynchronizationContext syncContext;
    public Timer()
    {
        syncContext = SynchronizationContext.Current;
    }

    public event EventHandler Tick;

    private void OnTick()
    {
        syncContext.Send(state =>
        {
            if (Tick != null)
                Tick(this, EventArgs.Empty);
        }, null);
    }

    //TODO other stuff to actually fire the tick event
}

这篇关于如何制作在主线程中触发事件的 C# 计时器?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆