Я думаю, у тебя довольно хороший Скотт.
Единственная небольшая проблема, с которой, я думаю, могут столкнуться некоторые, - это то, что вы блокируете поток, чтобы выполнить задержку. Конечно, это фоновый поток, и вряд ли он вызовет проблемы, если вы не выполняете много этих вызовов одновременно (каждый связывает поток), но он все еще, вероятно, неоптимальный.
Вместо этого я бы предложил вам включить алгоритм в служебный метод и избегать использования Thread.Sleep.
Очевидно, что существует множество способов сделать это, но вот один из них:
public static class UICallbackTimer
{
public static void DelayExecution(TimeSpan delay, Action action)
{
System.Threading.Timer timer = null;
SynchronizationContext context = SynchronizationContext.Current;
timer = new System.Threading.Timer(
(ignore) =>
{
timer.Dispose();
context.Post(ignore2 => action(), null);
}, null, delay, TimeSpan.FromMilliseconds(-1));
}
}
Для использования:
UICallbackTimer.DelayExecution(TimeSpan.FromSeconds(1),
() => textBlock.Text="Done");
Конечно, вы могли бы также написать реализацию этого метода DelayExecution, который использует другие типы таймеров, такие как WPF DispatcherTimer или класс WinForms Timer. Я не уверен, каковы будут компромиссы этих различных таймеров. Я предполагаю, что таймеры DispatcherTimer и WinForm будут по-прежнему работать в приложениях противоположного типа.
EDIT:
Перечитывая мой ответ, я думаю, что на самом деле мне хотелось бы учесть это в методе расширения, который работает в контексте синхронизации - если вы подумаете об этом, то более общим утверждением будет то, что вы должны быть в состоянии опубликовать работу вернуться к контексту синхронизации после некоторой задержки.
SynchronizationContext уже имеет метод post для работы с очередями, который исходный вызывающий не хочет блокировать по завершении. Нам нужна версия, которая публикует работу после задержки, поэтому вместо этого:
public static class SyncContextExtensions
{
public static void Post(this SynchronizationContext context, TimeSpan delay, Action action)
{
System.Threading.Timer timer = null;
timer = new System.Threading.Timer(
(ignore) =>
{
timer.Dispose();
context.Post(ignore2 => action(), null);
}, null, delay, TimeSpan.FromMilliseconds(-1));
}
}
и использование:
SynchronizationContext.Current.Post(TimeSpan.FromSeconds(1),
() => textBlock.Text="Done");