У меня есть фрагмент кода, который выполняет некоторые вычисления, а затем вызывает команду form.show. Теперь у меня есть библиотека (revit api), которая не позволяет мне хранить переменные в проекте, не находясь в основном потоке.
Логическим решением для этого является заставить порожденный поток вызывать основной поток, используя, скажем, шаблон производитель/потребитель с кодом, который выглядит примерно так:
form.Show(owner);
while(AppIsRunning){
if(clicked)
commit();
else
Thread.sleep(100);
}
Однако, когда я это делаю, графический интерфейс загружается не полностью (черный фон, нет текста в дополнительных кнопках).
Я также пытался сделать это, используя метод вызова
private void BtnOK_Click(object sender, System.EventArgs e)
{
Commit();
Invoke(Commit);
}
private void Invoke(Action commit)
{
commit.Invoke();
}
Однако это просто говорит мне, что это не основной поток, выполняющий функцию фиксации. Есть ли другой способ сделать это или я просто делаю ошибку.
Просто для ясности у меня есть команда form.show(owner), которая выдает ошибку, если она не выполняется основным потоком. У меня также есть функция commit(), которая должна быть оправдана основным потоком, иначе она выдает ошибку. Выполнение должно дождаться нажатия кнопки. Но основной поток, опрашивающий поток графического интерфейса для изменения, приводит к зависанию программы. Согласно моему поиску в Google, также возможно сделать что-то, связанное с внешним событием, чтобы вернуться в правильный контекст, но в приведенном примере использовалось использование python для вызова кода С#, есть ли хороший способ вызвать внешнее событие, чтобы вернуться в данный поток в С#?
Изменить: на основе некоторых предложений я создал следующий код:
public class ThreadManager
{
static List<ThreadAble> orders = new List<ThreadAble>();
public static bool running = false;
public static void execute(ThreadAble action)
{
orders.Add(action);
}
static System.Timers.Timer timer;
public static void RegisterAPIThreadAndHold(ExternalCommandData commandData)
{
UIApplication uiapp = commandData.Application;
uiapp.Idling += Application_Idle;
}
private static void Application_Idle(Object o,IdlingEventArgs e)
{
if (orders.Count != 0)
{
ThreadAble f = orders.First();
orders.Remove(f);
f.execute();
}
}
}
public interface ThreadAble {
void execute();
}
Однако на самом деле это не запускается, когда я использую его в качестве общедоступного переопределения Result Execute (ExternalCommandData commandData, сообщение строки ссылки, элементы ElementSet)
Form frm = new OverviewForm(ExternalCommandData commandData);
frm.show()
ThreadManager.RegisterAPIThreadAndHold(commandData);
ThreadManager.Execute(new run_ThrowError())
где ThrowError.execute() — это Throw new Exception («это фактически выполняется»);