如何在特定时间间隔后运行方法?

时间:2014-06-23 17:04:03

标签: c# multithreading winforms timer

很清楚:例如,假设我的表单中有一个按钮。当用户点击按钮时,一些void方法应在30秒后运行。

会有一个带有两个输入参数的void方法DoAfterDelay。第一个是要做的方法(使用委托),另一个是时间间隔。所以我会:

public delegate void IVoidDelegate();
static void DoAfterDelay(IVoidDelegate TheMethod, TimeSpan Interval)
    {
        // *** Some code that will pause the process for "Interval".
        TheMethod();
    }

所以,我只需要一段代码就可以暂停特定时间间隔的过程。到目前为止,我使用此代码执行此操作:

System.Threading.Thread.Sleep(Interval);

但这段代码对我没有好处,因为它会停止整个过程并冻结程序。我不希望程序陷入DoAfterDelay方法。这就是Thread.Sleep没用的原因。

那么有人可以提出更好的方法吗?当然我已经搜索过了,但我发现的大多数解决方案都是基于使用计时器(例如here)。但是使用计时器是我最后的意见,因为该方法应该运行一次并且使用计时器会使程序混淆读取。所以,如果有的话,我正在寻找更好的解决方案。或者我可能必须使用计时器?

我想我必须玩线程,但不确定。所以我想知道是否有人可以指导我找到解决方案。提前谢谢。

8 个答案:

答案 0 :(得分:13)

这是您可以使用.Net 4.5

的异步等待功能的地方

您可以使用Task.Delay以毫秒为单位给出延迟。 这是一种非常干净的方式。例如:

    private async void button1_Click(object sender, EventArgs e)
    {
        await Task.Delay(5000);

        TheMethod();
    }

答案 1 :(得分:11)

你能使用任务吗?

    Task.Factory.StartNew(() =>
    {
        System.Threading.Thread.Sleep(Interval);
        TheMethod();
    });

答案 2 :(得分:0)

DoAfterDelay启动一个只运行一次的计时器,当它到期时,它会调用你的空虚' TheMethod'功能。 为什么会这么乱?

答案 3 :(得分:0)

这就是你想要的:

    public static void Example1c()
    {
        Action action = DoSomethingCool;
        TimeSpan span = new TimeSpan(0, 0, 0, 5);

        ThreadStart start = delegate { RunAfterTimespan(action, span); };
        Thread t4 = new Thread(start);
        t4.Start();

        MessageBox.Show("Thread has been launched");
    }
    public static void RunAfterTimespan(Action action, TimeSpan span)
    {
        Thread.Sleep(span);
        action();
    }
    private static void DoSomethingCool()
    {
        MessageBox.Show("I'm doing something cool");
    }

使用Action的一个好处是可以轻松修改它以传入参数。假设您希望能够将整数传递给DoSomethingCool。只需修改即可:

    public static void Example1c()
    {
        Action<int> action = DoSomethingCool;
        TimeSpan span = new TimeSpan(0, 0, 0, 5);
        int number = 10;

        ThreadStart start = delegate { RunAfterTimespan(action, span, number); };
        Thread t4 = new Thread(start);
        t4.Start();

        MessageBox.Show("Thread has been launched");
    }
    public static void RunAfterTimespan(Action<int> action, TimeSpan span, int number)
    {
        Thread.Sleep(span);
        action(number);
    }
    private static void DoSomethingCool(int number)
    {
        MessageBox.Show("I'm doing something cool");
    }

非常灵活......

答案 4 :(得分:0)

有几种创建线程的方法,但当然,这取决于你在做什么。 您可以像这样动态创建一个线程:

Thread aNewThread = new Thread(
    () => OnGoingFunction()
);
aNewThread.Start();

此主题将在后台运行。你想要做的功能应该有一个睡眠方法,以便在完成处理后进入睡眠状态。所以像这样:

private void OnGoingFunction()
{
   //Code....
   Thread.Sleep(100); //100 ms, this is in the thead so it will not stop your winForm
   //More code....
}

我希望有所帮助。

另一个选择是在需要处理它时创建线程,而不用担心sleep选项。每次只需创建一个新线程来加载进程

答案 5 :(得分:0)

您应该创建Coroutine

public IEnumerator waitAndRun()
{
    // WAIT FOR 3 SEC
    yield return new WaitForSeconds(3);
    // RUN YOUR CODE HERE ...
}

并将其命名为:

StartCoroutine(waitAndRun());

答案 6 :(得分:0)

您可以使用来指定确切的秒数

DateTime runTime = new DateTime();
double waitSeconds = (runTime - DateTime.Now).TotalSeconds;

Task.Factory.StartNew(() =>
{
    Thread.Sleep(TimeSpan.FromSeconds(waitSeconds));
    YourMethod();
});

runTime =>当您要执行该方法时。

答案 7 :(得分:-1)

这是一个针对 Dispatcher 的简单扩展,您可以以非阻塞方式使用。

public static void InvokeAfter(this Dispatcher dispatcher, int milliseconds, Action delayedAction) {

    Task.Factory.StartNew(() => {
        System.Threading.Thread.Sleep(milliseconds);
        dispatcher.Invoke(delayedAction);
    });
}

这里是如何将它与 Lambda 一起使用:

SomeLabel.Dispatcher.InvokeAfter(3000, () => {
    SomeLabel.Text = "Hello World";
});

您也可以将它与任何匹配 Action 的内容一起使用。这是使用本地函数的示例...

void doLater(){
    SomeLabel.Text = "Hello World";
}

// Pass the action itself, not the result of the action (i.e. don't use parentheses with 'doLater'.)
SomeLabel.Dispatcher.InvokeAfter(3000, doLater);

注意:然后您可以针对通常调用 Invoke 的任何调度程序对象调用它。为了安全起见,我喜欢使用处理我正在更新的控件的调度程序来调用它。