Звучит сложно!
Вы говорите, что ваш источник данных не является потокобезопасным. Итак, что это значит для пользователя. Если они щелкают повсюду, но не ждут загрузки свойств, прежде чем щелкнуть где-то еще, они могут щелкнуть по 10 узлам, которые долго загружаются, и затем сидеть в ожидании 10-го. Загрузка должна выполняться одна за другой, поскольку доступ к источнику данных не является потокобезопасным. Это указывает на то, что ThreadPool не будет хорошим выбором, поскольку он будет запускать нагрузки параллельно и нарушать безопасность потоков. Было бы хорошо, если бы загрузка могла быть прервана на полпути, чтобы пользователю не приходилось ждать загрузки последних 9 узлов, прежде чем начнется загрузка страницы, которую он хочет видеть.
Если загрузка может быть прервана, я бы посоветовал использовать BackgroundWorker. Если пользователь переключает узел, и BackgroundWorker уже занят, установите событие или что-то, сигнализирующее, что оно должно прервать существующую работу, а затем поставьте в очередь новую работу для загрузки текущей страницы.
Кроме того, учтите, что запуск потока в пуле потоков не слишком сложен. Для этого передайте объект прогресса в вызов QueueUserWorkItem типа, подобного следующему:
class Progress
{
object _lock = new Object();
int _current;
bool _abort;
public int Current
{
get { lock(_lock) { return _current; } }
set { lock(_lock) { _current = value; } }
}
public bool Abort
{
get { lock(_lock) { return _abort; } }
set { lock(_lock) { _abort = value; } }
}
}
Поток может писать в это, а поток пользовательского интерфейса может опрашивать (из события System.Windows.Forms.Timer), чтобы прочитать прогресс и обновить индикатор выполнения или анимацию.
Кроме того, если вы включите свойство Abort. Пользовательский интерфейс может установить его, если пользователь меняет узел. Метод load может в различных точках на протяжении всей своей работы проверять значение сброса и, если он установлен, возвращаться без завершения загрузки.
Если честно, то, что вы выбираете, не имеет никакого значения. Все три варианта делают вещи в фоновом потоке. На вашем месте я бы начал с BackgroundWorker, так как он довольно прост в настройке, и если вы решите, что вам нужно что-то еще, подумайте о том, чтобы потом переключиться на ThreadPool или обычный поток.
BackgroundWorker также имеет то преимущество, что вы можете использовать его завершенное событие (которое выполняется в основном потоке пользовательского интерфейса) для обновления пользовательского интерфейса загруженными данными.