【问题标题】:How do you make threaded GUI applications in WinForms correctly?如何在 WinForms 中正确制作线程化 GUI 应用程序?
【发布时间】:2011-08-05 10:01:47
【问题描述】:

我来自 C 背景,目前我想制作一个具有响应式 GUI 和长时间运行的工作线程的小型 WinForms 实用程序。

GUI 是常规的 Form1 派生的东西,带有进度指示器和东西,工作线程类似于 new System.Threading.Thread();

在 C++ 中一切都很简单,在 .NET 中我不知道该怎么做。

是否有 PostMessage 类型的数据更新方式?我是否在读取共享锁保护结构的主线程上踢了一个计时器,还有另一种方法吗?看到了有关代表的多个文档,但在 10 篇不同的文章之后,它们似乎不起作用,可能是因为我有一个 WorkerGUI 关系,而不是一个 GUIGUI 关系。

所有 GUI 的东西都在 GUI 类中,所有工作人员的东西都在它自己的工作人员类中。托管世界中的最佳实践是什么?

【问题讨论】:

    标签: .net winforms multithreading


    【解决方案1】:
    1. 使用 BackgroundWorker
    2. 使用 Control.Invoke
    3. 使用 SynchronizationContext
    4. 使用任务并行库 (System.Threading.Tasks)
    5. 使用 Rx
    6. 不要使用 Thread.Start 或 ThreadPool

    【讨论】:

    • 级别很低。太低,无法在程序中使用。
    • “太低了”,那又怎样?这不是组装 :)
    • 很好的比喻。手动创建线程类似于并行和异步执行的汇编语言。
    • 我来自 C/C++ 背景,我发现低级的东西更有效率,更容易理解。好吧,也许只有我一个人知道。
    • 就我个人而言,我不使用 BackgroundWorker,因为它感觉像是一个不必要的层而没有提供任何好的好处,另一方面,线程可以直接启动,可以在 2 行代码中启动,完成后你只需更新图形用户界面。
    【解决方案2】:

    这是WinForms Application中的程序类

     static class Program
            {
                /// <summary>
                /// The main entry point for the application.
                /// </summary>
                [STAThread]
                static void Main()
                {
                    Application.EnableVisualStyles();
                    Application.SetCompatibleTextRenderingDefault(false);
                    Application.Run(new Form1());
                }
            }
    

    这里只有一个线程[STAThread]

    你可以使用[MTAThread]代替它,这样可以处理多个线程

    或者可以使用System.Threading创建线程运行时

    【讨论】:

    • 好的,但是worker是通过按钮点击创建的,所以他们被调度到线程池或者从Form1交互通过线程启动启动。所以我仍然必须在 [STAThread] 中,对吗?顺便说一句,不是 STA/MTA COM 的东西吗?所以基本上,既然它是一个 GUI 应用程序,那么 GUI 线程(运行 Main 和后来泵 Form1 的那个)无论如何都必须是 STA 线程?
    【解决方案3】:

    有很多方法,但很简单,

    • 启动线程
    • 使用 InvokeRequired 和 Invoke() 返回 GUI 线程

    另外BackgroundWorker 提供了一种更简单的方法。

    【讨论】:

    • 如果我理解正确,那么在这种情况下,数据处理库拥有 GUI,它会执行“不时更新 GUI”。我正在寻找的更像是 GUI[进度存储]Logic&DataLayer。 GUI 在哪里启动 DataProcessing,但如果有新的进程存储数据可用,则检查事件,如果可用,则相应地更新 GUI 元素。有这样的可能吗?
    • 然后启动一个新线程,使用GUI可以直接访问的共享对象(这样GUI可以插入东西)和新线程。如果您愿意,可以向线程发出信号通知更新,因此线程将处理新的更新并调用 Control.Invoke() 来更新 GUI
    • 是的,这就是我所期待的,但是如果 .NET 中没有 PostMessage 架构,我如何向 GUI 发出信号?
    • 所有你需要做的就是Control.Invoke(YourFunction) 没有别的,PostMessage 等都在后台为你发生。
    • 我尝试将Form1 的引用传递给worker,然后调用MethodInvoker action = delegate { Form1.UpdateGUI(); }; Form1.BeginInvoke(action);。而且还是有异常调用是从错误的线程完成的。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-01-11
    • 1970-01-01
    相关资源
    最近更新 更多