C# 有没有办法在 Windows 窗体中延迟事件处理程序(比如 1 秒)

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/648700/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-04 11:43:02  来源:igfitidea点击:

Is there a way to delay an event handler (say for 1 sec) in Windows Forms

c#.netwinformsevents

提问by

I need to be able to delay the event handlers for some controls (like a button) to be fired for example after 1 sec of the actual event (click event for example) .. is this possible by the .net framework ?

我需要能够延迟某些控件(如按钮)的事件处理程序,例如在实际事件(例如单击事件)发生 1 秒后触发。.net 框架是否可以实现这一点?

I use a timer and call my code from the timer's tick event as below but I am not sure if this is the best approach !

我使用计时器并从计时器的滴答事件中调用我的代码,如下所示,但我不确定这是否是最好的方法!

void onButtonClick( ..)
{
   timer1.Enabled = true;
}

void onTimerTick( ..)
{
   timer.Enabled = false; 

   CallMyCodeNow();
}

回答by Jon Skeet

Before coming to your question, just having read the summary bit from the main questions page, a timer was exactly what I was going to suggest.

在回答你的问题之前,刚刚阅读了主要问题页面的摘要部分,计时器正是我要建议的。

This looks pretty clean to me. It means you can easily "cancel" the delayed event if you need to, by disabling the timer again, for example. It also does everything within the UI thread (but without reentrancy), which makes life a bit simpler than other alternatives might be.

这对我来说看起来很干净。这意味着您可以在需要时轻松“取消”延迟事件,例如再次禁用计时器。它还可以在 UI 线程中执行所有操作(但没有重入性),这使生活比其他替代方案更简单一些。

回答by MRFerocius

You can use:

您可以使用:

Thread.Sleep(1000);

That will pause the current Thread for one second. So I would do that...

这将使当前线程暂停一秒钟。所以我会这样做...

Best Regards!

此致!

回答by Bengt

Perhaps you could make a method that creates the timer?

也许您可以制作一个创建计时器的方法?

void onButtonClick(object sender, EventArgs e)
{
    Delay(1000, (o,a) => MessageBox.Show("Test"));
}

static void Delay(int ms, EventHandler action)
{
    var tmp = new Timer {Interval = ms};
    tmp.Tick += new EventHandler((o, e) => tmp.Enabled = false);
    tmp.Tick += action;
    tmp.Enabled = true;
}

回答by Robert Rossney

If you're only doing this for one control, the timer approach will work fine. A more robust approach supporting multiple controls and types of events looks something like this:

如果您只为一个控件执行此操作,则计时器方法将正常工作。支持多种控件和事件类型的更强大的方法如下所示:

class Event
{
   public DateTime StartTime { get; set; }
   public Action Method { get; set; }

   public Event(Action method)
   {
      Method = method;
      StartTime = DateTime.Now + TimeSpan.FromSeconds(1);
   }
}

Maintain a Queue<Event>in your form and have UI events that need to be delayed add them to the queue, e.g.:

Queue<Event>在您的表单中维护 a并将需要延迟的 UI 事件添加到队列中,例如:

void onButtonClick( ..)
{
   EventQueue.Enqueue(new Event(MethodToCall));
}

Make your timer tick 10 times a second or so, and have its Tick event handler look like this:

使您的计时器每秒滴答 10 次左右,并使其 Tick 事件处理程序如下所示:

void onTimerTick()
{
   if (EventQueue.Any() && EventQueue.First().StartTime >= DateTime.Now)
   {
      Event e = EventQueue.Dequeue();
      e.Method;
   }
}

回答by Tomas Petricek

If you're looking for a more fancy solution, you may want to take a look at my Reactive LINQ project. The link doesn't show how to solve the particular problem you're having, but it should be possible to solve in quite an elegant style using the technique described there (in the whole 4-article series).

如果您正在寻找更奇特的解决方案,您可能需要查看我的 Reactive LINQ 项目。该链接没有显示如何解决您遇到的特定问题,但应该可以使用那里描述的技术以相当优雅的方式解决(在整个 4 篇文章系列中)。

回答by Boris Lipschitz

My solution uses System.Threading.Timer:

我的解决方案使用 System.Threading.Timer:

public static class ExecuteWithDelay
{
    class TimerState
    {
        public Timer Timer;
    }

    public static Timer Do(Action action, int dueTime)
    {
        var state = new TimerState();
        state.Timer = new Timer(o =>
        {
            action();
            lock (o) // The locking should prevent the timer callback from trying to free the timer prior to the Timer field having been set.
            {
                ((TimerState)o).Timer.Dispose();
            }
        }, state, dueTime, -1);
        return state.Timer;
    }
}

回答by Steve Cadwallader

For those limited to .NET 2.0, here is another take on Bengt's helpful solution:

对于那些仅限于 .NET 2.0 的人,这里是 Bengt 有用的解决方案的另一种看法:

/// <summary>
/// Executes the specified method in a delayed context by utilizing
/// a temporary timer.
/// </summary>
/// <param name="millisecondsToDelay">The milliseconds to delay.</param>
/// <param name="methodToExecute">The method to execute.</param>
public static void DelayedExecute(int millisecondsToDelay, MethodInvoker methodToExecute)
{
    Timer timer = new Timer();
    timer.Interval = millisecondsToDelay;
    timer.Tick += delegate
                      {
                          // This will be executed on a single (UI) thread, so lock is not necessary
                          // but multiple ticks may have been queued, so check for enabled.
                          if (timer.Enabled)
                          {
                              timer.Stop();

                              methodToExecute.Invoke();

                              timer.Dispose();
                          }
                      };

    timer.Start();
}

回答by fiat

Using Reactive Extensions:

使用反应式扩展:

First, install the nuget package

首先,安装nuget包

PM> Install-Package Rx-Main

Code:

代码:

    private void CallMyCodeNow()
    {
        label1.Text = "reactivated!";
    }

    private void Form1_Load(object sender, EventArgs e)
    {
        var o = Observable.FromEventPattern<EventHandler, EventArgs>(
            handler => button1.Click += handler
            , handler => button1.Click -= handler
            )
            .Delay(TimeSpan.FromSeconds(5))
            .ObserveOn(SynchronizationContext.Current)  // ensure event fires on UI thread
            .Subscribe(
                ev => CallMyCodeNow()
                , ex => MessageBox.Show(ex.Message)
            );
    }