这是我的目标:该应用程序由一个表单 - MainForm - 组成,其中包含许多选项卡(类似于 Notepad++ GUI)。每个选项卡都是一个 UserControl 后代 (UCDx)。 MainForm 可以显示 2 个或更多包含相同 UCDx 实例的选项卡。目标是 UCDx 必须执行一些耗时的操作或方法执行 - 即数据库读/写、Web 服务方法调用。我希望在单独的线程中运行此类操作,以免卡住 UI。此外,我还需要实现一个信息表单(InfoForm) - 它将显示当前运行线程的信息,并具有一些交互功能 - 即关闭运行时间过长的线程。
我面临的主要问题是:
- 与 GUI 的线程交互 - 即线程读取应显示在网格中的数据;
- 线程交互管理 - 在实现 InfoForm 时。
在并发/并行编程中,我是初学者 - 有人可以提供一些关于如何实现它的线索吗?
最佳答案
我首先将工作逻辑与 UI 分开。
例如,对于“需要读取数据并显示数据的线程”,请尝试将问题分成更小的部分:
创建一个普通类,它具有同步处理方法,不涉及线程。像这样的东西:
interface IServiceReader { Data GetDataFromService(IServiceInfo info); }
测试一下。创建单元测试,甚至是一个小型控制台应用程序,您可以在其中看到它在没有 GUI 的情况下也能正常工作。
创建一个异步包装类,它调用
ServiceReader
来完成这项工作,但在后台线程上调用它,并在完成后触发一个事件。interface IAsyncServiceReader { void Start(IServiceInfo info); event EventHandler<Data> DataReceived; }
再次测试一下。这应该是一个单独的类库,独立于您的 GUI。
使用 MVC 或类似模式将 View (选项卡)与模型(异步服务读取器)分开。这意味着您应该从 View 中触发交互事件,在 Controller 中处理它们,然后让 Controller 在模型中调用适当的操作:
class Controller { readonly ITabView _view; readonly IAsyncServiceReader _model; public Controller(ITabView view, IAsyncServiceReader model) { _view = view; _model = model; AttachHandlers(); } void AttachHandlers() { view.UserRequestedLoading += (sender,info) => model.Start(info); model.DataReceived += (sender,data) => view.DisplayData(data); } }
最后,确保后台线程调用被分派(dispatch)到正确的 (GUI) 线程。这仅仅意味着您的选项卡 View 需要检查是否需要调用:
class TabView : UserControl { void DisplayData(Data data) { if (this.InvokeRequired) { BeginInvoke(new Action<Data>(DisplayData), data); return; } // otherwise, display the data in some way dataGrid.DataSource = data; ... } }
将模型与 View 分离将简化测试以及以后对 UI 的更改。您可以决定将其设为控制台应用程序或 Windows 服务,这将使您的业务逻辑保持完整。
关于c# - 管理 .NET WinForm 应用程序中的线程,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7834378/