Вот очень простой одиночный элемент, который просто генерирует дату/строку времени:
class TheDate
{
private static $DateInstance = null;
private $dateVal;
public static function getDateInstance()
{
if(!isset(self::$DateInstance))
{
self::$DateInstance = new TheDate();
}
return self::$DateInstance;
}
public static function getDateVal()
{
return self::$DateInstance->dateVal;
}
private function __construct()
{
$this->dateVal = strftime("%Y-%m-%d %H:%M:%S");
}
}
Выполнение чего-то вроде этого, очевидно, дает мне ту же дату много раз:
$date1 = TheDate::getDateInstance();
echo $date1->getDateVal() . "<br />";
$date2 = TheDate::getDateInstance();
echo $date2->getDateVal() . "<br />";
И выполнение этого не генерирует ошибок:
class NewDate extends TheDate
{
public function __construct()
{
}
}
В этом примере обновляется индикатор выполнения:
using System;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
class SimpleProgressBar : Form
{
[STAThread]
static void Main(string[] args)
{
Application.EnableVisualStyles();
Application.Run(new SimpleProgressBar());
}
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
int iterations = 100;
ProgressBar pb = new ProgressBar();
pb.Maximum = iterations;
pb.Dock = DockStyle.Fill;
Controls.Add(pb);
Task.ContinueWith(delegate
{
Parallel.For(0, iterations, i =>
{
Thread.SpinWait(50000000); // do work here
BeginInvoke((Action)delegate { pb.Value++; });
});
});
}
}
The TPL isn't particularly oriented toward UI support, you can (still) use a BackgroundWorker for that. As for sending or processing intermediate results, there are new collectionclasses (ConcurrentQueue) to support that.
Для этого нет встроенной поддержки, такой как у BackgroundWorker.
Вы можете использовать SynchronizationContext напрямую; здесь есть отличное видео: http://www.rocksolidknowledge.com/ScreenCasts.mvc/Watch?video=TasksAndThreadAffinity.wmv
В этом видео автор разрабатывает два решения: одно с использованием SynchronizationContext а другой - с помощью продолжения задач. Для вашей проблемы продолжения не будут работать, но подход SynchronizationContext будет работать нормально.
P.S. Если вы создаете повторно используемый код, то при захвате SynchronizationContext.Current вам следует проверить наличие null и (если он равен null) вместо этого использовать созданный по умолчанию SynchronizationContext.
ОБНОВЛЕНИЕ : я разместил код для этого в моем блоге . Мое решение фактически основано на Задаче
, которая запланирована обратно в поток пользовательского интерфейса TaskScheduler
, который использует SynchronizationContext
внизу. В отличие от принятого ответа, это решение будет работать как для WPF, так и для Windows Forms.