И если мы в этом цикле будем что то делать из другого потока, то ожидаемо рано или поздно получим либо ошибку, что нельзя работать из другого потока, либо Revit тупо вылетит.
Прошу прощения, только сейчас заметил, что в коде только прогресс бар вызывается из другого потока, а Revit API вызывается в основном потоке.
Я такую задачу успешно решил. Алгоритм примерно следующий.
1) Форма открывается в основном потоке
2) При открытии формы или при нажатии на кнопку на этой форме запускается некая команда, в которой выполняется длительный процесс. Этот длительный процесс запускаю с помощью
Task в другом потоке.
3) Тут проблема в том, что запустив длительный процесс в другом потоке, нельзя вызывать команды Revit API. Поэтому в тот момент, когда в цикле нужно обратиться к методам Revit API, эти методы я вызываю из ОСНОВНОГО потока. Таким образом, получаются безопасные вызовы к методам Revit API.
4) Кнопка отмены доступна в тот момент, когда не вызываются методы Revit API.
Псевдокод примерно такой
// метод вызывается при нажатии на кнопку или при запуске формы и запускает долгий процесс
private void btn1_OnClick()
{
Task longTask =
new Task(DoSomething);
// запустили долгую задачу в отдельном процессе
longTask.Run();
}
void DoSomething()
{
foreach(var i in collection)
{
// тут делаем что то с помощью Revit API, но нужно делать это в ОСНОВНОМ потоке. CallRevitAPI вызывает методы в ОСНОВНОМ потоке
CallRevitAPI(()=> {doc.GetElement(id);})
if (cancelled)
return;
}
}
//кнопка Cancel доступна, так как долгая задача в другом потоке.
void btnCancel_OnClick()
{
cancelled = true;
}
Когда я реализовывал подобный подход, основная сложность была как правильно передать основной поток, находясь в другом потоке. Это тоже успешно решается. Я постараюсь набросать тестовый пример, выдрав из моего основного проекта.
Явно где-то не хватает Application.DoEvents()
Рискую начать холивар, но вроде как это
bad practice