Ответ 1
Вы можете использовать System.Timers.Timer: установить AutoReset в значение false и использовать методы Start/Stop и создать обработчик для события Elapsed.
Есть ли простое решение/идея/стратегия для создания эквивалентной функции setTimeout в приложении WinForms. Я в первую очередь веб-разработчик, но не уверен, как это сделать в приложении WinForms. В принципе, у меня есть текстовое поле, и после каждого нажатия клавиши я хочу запустить задачу, чтобы заполнить список (например, auto-complete type thingy), но хочу иметь возможность отменить (например, clearTimeout), если пользователь продолжает вводить символы...
Мое единственное предположение - возможно, использовать BackGroundWorker и сначала скомпоновать его, и пока он спит, его можно отменить, если пользователь перестает вводить ключи и заканчивается период ожидания, затем он запускает и запускает задачу и т.д.
(мне все равно, что пример С# или Vb.Net)
Вы можете использовать System.Timers.Timer: установить AutoReset в значение false и использовать методы Start/Stop и создать обработчик для события Elapsed.
Я знаю, что это старый вопрос, но альтернативным решением было бы использовать Task.Delay(delay).ContinueWith((task) => { /* Code */ });
.
или существует await Task.Delay(delay);
public void setTimeout(Action TheAction, int Timeout)
{
Thread t = new Thread(
() =>
{
Thread.Sleep(Timeout);
TheAction.Invoke();
}
);
t.Start();
}
Я могу предложить следующее
internal class Timeout : System.Timers.Timer
{
public Timeout (Action action, double delay)
{
this.AutoReset = false;
this.Interval = delay;
this.Elapsed += (sender, args) => action();
this.Start();
}
}
// Example
var timeout = new Timeout(() => {
Console.WriteLine("init 1");
}, 500);
timeout.Stop();
Реализация таймера:
public void SetTimeout(Action action, int timeout)
{
var timer = new System.Windows.Forms.Timer();
timer.Interval = timeout;
timer.Tick += delegate (object sender, EventArgs args)
{
action();
timer.Stop();
};
timer.Start();
}
public void setTimeout(Action act, int timeout)
{
Action action = () =>
{
Thread.Sleep(Timeout);
act();
};
new Thread(() => Invoke(action)).Start();
}
Я бы рекомендовал использовать для этого реактивное программирование. См. https://github.com/Reactive-Extensions/Rx.NET для реактивных расширений для .NET и http://reactivex.io/ для общей информации об активном программировании.
Я боюсь, что я знаком с реактивной библиотекой JavaScript, поэтому я не могу дать вам пример C-Sharp, но в JavaScript он будет работать примерно так:
Rx.Observable.fromEvent(..eventdetails..)
.debounceTime(300)
.distinctUntilChanged()
.subscribe(eventHandler);
Используя такую настройку, вы можете привязать операторов к отображению и объединению всех видов событий от источника к подписчику. Простой пример выше относится к событию, например keyUp, и ожидает, пока не будет нового keyUp за 300 мс, а затем вызовет eventHandler, но только если новое значение (после 300 мс) отличается от последнего испущенного значения.
Это мой путь, используйте синтаксис С# 7.0. Некоторые отличаются js, когда действие тайм-аута выполняется, тогда не может быть ясно.
internal static class JsStyleTimeout
{
private static readonly ConcurrentDictionary<int, Thread> InnerDic;
private static int _handle;
static JsStyleTimeout()
{
InnerDic = new ConcurrentDictionary<int, Thread>();
}
public static int Set(Action action, int delayMs)
{
var handle = Interlocked.Increment(ref _handle);
var thread = new Thread(new ThreadStart(delegate
{
Thread.Sleep(delayMs);
InnerDic.TryRemove(handle, out var _);
Task.Factory.StartNew(action);
}));
InnerDic.TryAdd(handle, thread);
thread.Start();
return handle;
}
public static void Clear(int handle)
{
if (InnerDic.TryRemove(handle, out var thread))
thread.Abort();
}
}
Вы также можете использовать:
Delay.Do(3000 /*in ms*/, () => { /* Do somthing */ });
Где Delay.Do
находится:
using System;
using System.Timers;
public class Delay
{
public static void Do(int after, Action action)
{
if (after <= 0 || action == null) return;
var timer = new Timer { Interval = after, Enabled = false };
timer.Elapsed += (sender, e) =>
{
timer.Stop();
action.Invoke();
timer.Dispose();
GC.SuppressFinalize(timer);
};
timer.Start();
}
}
Примечание: при обновлении элемента управления в потоке пользовательского интерфейса используйте Control.Invoke
:
Delay.Do(2000, () => { lblOk.Invoke((MethodInvoker)(() => { lblOk.Visible = false; })); });