很清楚:例如,假设我的表单中有一个按钮。当用户点击按钮时,一些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)。但是使用计时器是我最后的意见,因为该方法应该运行一次并且使用计时器会使程序混淆读取。所以,如果有的话,我正在寻找更好的解决方案。或者我可能必须使用计时器?
我想我必须玩线程,但不确定。所以我想知道是否有人可以指导我找到解决方案。提前谢谢。
答案 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
的任何调度程序对象调用它。为了安全起见,我喜欢使用处理我正在更新的控件的调度程序来调用它。