如何从不同的线程/类启用定时器

4

原帖:如何在C#中从另一个类访问计时器

我尝试了所有方法。

-事件

-无法使用Invoke,因为计时器没有InvokeRequired属性。

-公有/内部属性

什么都不起作用,代码正在执行,计时器的Enabled属性被设置为“true”,但它不会Tick。如果我在非静态方法中从表单类调用事件或只更改属性,则会Tick并正常工作。

我从未想到学习如何使用一个体面的计时器需要花费我一天甚至更多的时间。

如果没有办法做到这一点,是否有其他可以像计时器一样工作(延迟,启用/禁用)的东西可供使用?


John,请将这个内容添加到您之前的问题中(您可以编辑您的帖子),因为这对于其他遇到相同问题的用户会更有帮助。 - Dirk Vollmar
可能是 http://stackoverflow.com/questions/725413 的重复问题,如何在 C# 中从另一个类访问计时器。 - raven
4个回答

10

1
虽然这样做可以触发Elapsed事件(System.Timer.Timer具有Elapsed事件,而不是System.Windows.Forms.Timer的Tick事件),但它将在调用线程的上下文中触发,并且根据您在事件中执行的操作,可能会导致System.InvalidOperationException,例如“无效的跨线程操作:从创建它的线程以外的线程访问控件'X'。” - raven
天才,我在上面浪费了一整天时间。从来不知道 Windows 表单计时器的怪癖。 - nawfal
太棒了!对我有用。 - Imran Yaseen

6

您不需要在控件本身上检查 InvokeRequired,您可以在类上检查该属性,例如:

if (this.InvokeRequired) 
{ 
    BeginInvoke(new MyDelegate(delegate()
    {
        timer.Enabled = true;
    }));
}

1

我不小心又尝试了一次调用,这次它起作用了,但我会接受你的答案,DavidM。

    public bool TimerEnable
    {
        set
        {
            this.Invoke((MethodInvoker)delegate
            {
                this.timer.Enabled = value;
            });
        }
    }


    public static void timerEnable()
    {
        var form = Form.ActiveForm as Form1;
        if (form != null)
            form.TimerEnable = true;
    }

如果你的计时器在另一个类中怎么办?你将无法使用 this 调用。我认为一种可扩展的方法是由 @David M 提出的。 - nawfal

1

仅仅因为 System.Windows.Forms.Timer 没有调用的能力,并不意味着你的窗体没有。尝试使用我的 InvokeEx 方法来自第二个(或其他)线程启用计时器。

public static class ControlExtensions
{
  public static TResult InvokeEx<TControl, TResult>(this TControl control,
                            Func<TControl, TResult> func)
    where TControl : Control
  {
    if (control.InvokeRequired)
    {
      return (TResult)control.Invoke(func, control);
    }
    else
    {
      return func(control);
    }
  }
}

有了这个,以下的代码对我起作用:

new Thread(() =>
  {
    Thread.Sleep(1000);
    this.InvokeEx(f => f.timer1.Enabled = true);
  }).Start();

1秒后,计时器立即开始工作。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接