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

24

很明显:例如,想象一下我的表单中有一个按钮。当用户单击该按钮时,应在30秒后运行某些无返回值的方法。

会有一个名为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是无用的。

那么有人能建议一个更好的方法吗?当然我已经搜索过了,但我找到的大多数解决方案都是基于使用计时器(例如这里)。但是使用计时器是我的最后选择,因为该方法应该只运行一次,使用计时器会使程序难以阅读。所以如果有更好的解决方案,我正在寻找它。或者我必须使用计时器吗?

我猜我必须玩弄线程,但不确定。所以我想知道是否有人能引导我找到一个解决方案。先谢谢了。

8个回答

22

你能使用任务吗?

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


谢谢回答。所以实际上使用线程来解决问题。 - Mostafa Farzán
6
让线程闲置等待一段时间只是为了在此之后执行某些代码非常低效浪费。 - Servy
这种情况通常是当用户点击按钮时发生的,因此不会造成太大的负担,因为这不会经常发生。否则我建议编写一个任务调度程序。 - Bartosz Wójtowicz
System.Threading.Tasks.Task,但仍然出现错误:跨线程操作无效:从创建它的线程以外的线程访问控件'panel1'。 - TomeeNS
在任务线程上,您无法修改控件的属性。为此,您必须使用调度程序在 UI 线程上更新属性。 - Bartosz Wójtowicz
使用这个方法,您将在池中拥有一个几乎不做任何事情但占用资源的线程。 - Sayed Muhammad Idrees

22

这是您可以使用 .Net 4.5 的异步等待功能的地方。

您可以使用 Task.Delay 并给出以毫秒为单位的延迟时间。 这是一个非常简洁的方法。例如:

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

    TheMethod();
}

1
你应该创建一个 Coroutine
public IEnumerator waitAndRun()
{
    // WAIT FOR 3 SEC
    yield return new WaitForSeconds(3);
    // RUN YOUR CODE HERE ...
}

并使用以下代码进行调用:

StartCoroutine(waitAndRun());

1

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

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

这个线程将在后台运行。你想要执行的函数应该有一个sleep方法,在处理完之后休眠。所以代码大概是这样的:

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

我希望这有所帮助。 另一种选择是在需要处理线程时创建它,不必担心休眠选项。每次加载进程时都创建一个新线程。

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

非常灵活...

0

DoAfterDelay启动一个只运行一次的计时器,当它到期时调用您的void 'TheMethod'函数。为什么会很混乱?


0

您可以使用以下方式指定确切的秒数:

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

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

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


-2
这是一个针对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一样。为了安全起见,我喜欢使用处理我正在更新的控件的调度程序来调用它。

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