c# - 在 form.show 之后让主线程在按下按钮时执行代码

标签 c# multithreading user-interface producer-consumer revit-api

我有一段代码可以进行一些计算,然后调用 form.show 命令。现在我有一个库(revit api),它不允许我在不在主线程中的情况下将变量存储在项目中。

逻辑上的解决方案是让生成的线程使用生产者/消费者模式调用主线程,代码看起来有点像这样:

form.Show(owner);
while(AppIsRunning){
    if(clicked)
        commit();
    else   
        Thread.sleep(100);
}

但是,当我这样做时,GUI 不会完全加载(黑色背景,按钮中没有文本)。

我也试过使用唤起方法来做到这一点

    private void BtnOK_Click(object sender, System.EventArgs e)
    {
        Commit();
        Invoke(Commit);
    }

    private void Invoke(Action commit)
    {
        commit.Invoke();
    }

然而,这只是告诉我执行提交函数的不是主线程。 有没有其他方法可以做到这一点,或者我只是犯了一个错误。

需要说明的是,我有一个 form.show(owner) 命令,如果它没有被主线程执行,它会抛出一个错误。我还有一个 commit() 函数,它必须被主线程原谅,否则它会抛出错误。执行必须等到按下按钮。但是主线程轮询 gui 线程进行更改会导致程序挂起。根据我的谷歌搜索,也可以做一些涉及外部事件的事情来回到正确的上下文,但给出的例子是使用 python 调用 c# 代码,是否有引发外部事件以返回的好方法c# 中的给定线程?

编辑:根据一些建议,我创建了以下代码:

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();        
}

然而,当我将它用作 public override Result Execute(ExternalCommandData commandData, ref string message, ElementSet elements)

   Form frm = new OverviewForm(ExternalCommandData commandData);
   frm.show()
    ThreadManager.RegisterAPIThreadAndHold(commandData);
    ThreadManager.Execute(new run_ThrowError())

ThrowError.execute() 在哪里 Throw new Exception("这实际上正在被执行");

最佳答案

如果您将 Thread.Sleep 替换为 System.Windows.Forms.Application.DoEvents(),您的第一个示例可能会起作用。它应该给绘制 GUI 的时间,并且不要完全卡住应用程序。

form.Show(owner);
while(AppIsRunning){
    if(clicked)
        commit();
    else   
    {
        System.Windows.Forms.Application.DoEvents();
        // Thread.sleep(100);
    }
}

但这并不是实现这一目标的完美解决方案。 更好的做法是在对话框中调用 Dispatcher.Invoke 命令来执行 MainThread 操作。 您可以使用 GalaSoft 库 - 请参阅 DispatcherHelper 对象文档和示例。

关于c# - 在 form.show 之后让主线程在按下按钮时执行代码,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40379380/

相关文章:

c# - WPF ContentControl 无法从 ViewModel 解析正确的 View (Catel)

c# - Quartz.Net在Mono中启动线程卡住系统

algorithm - 如何有效地调试共享内存中的引用计数问题?

c# - 可以使 C# DateTime.TryParse 需要日、月和年吗?

c# - 如何克服 PathTooLongException?

c# - InstallFinalize 后 WIX 自定义操作修改 INSTALLFOLDER 中的文件

java - 将 Libgdx 滚动条添加到 TextArea

python:X 服务器上的致命 IO 错误 11(资源暂时不可用):0.0

java - java 中的预测文本

java - 在 eclipse 中将 JFreeChart 添加到 Maven