1

当我的 MainForm 正在做一些与数据库相关的工作时,我想显示一个带有进度条的新表单。我读到您不想将 UI 传递给新线程,所以我想知道解决此问题的最佳解决方案是什么?

我不能在另一个线程上做与数据库相关的工作,因为它使用了十几个对 UI 和 MainForm 的调用。我也不能使用Application.DoEvents(),因为 MainForm 的线程在一个类中工作,据我所知,你不应该对类的父级进行任何调用。

任何建议,将不胜感激!

编辑

为了澄清我真正想知道的:

我的程序看起来有点像这样:

... Content = DatabaseClass.LoadContent();
ApplyContentToUI(Content);

我想做的是以下几点:

//Show a form here with a progressbar
... Content = DatabaseClass.LoadContent();
ApplyContentToUI(Content);
//Close the form here

但是由于执行 ApplyContentToUI 的时间是 aprox。1秒我决定做以下事情:

//Show a form here with a progressbar
... Content = DatabaseClass.LoadContent();
//Close the form here
ApplyContentToUI(Content);

如果您与我不同,需要在重新加载 UI 时显示进度条,我建议您查看下面的评论和答案。

4

2 回答 2

9

我不能在另一个线程上做与数据库相关的工作

错误的。

推荐:

正如许多人在评论中提到的那样,您应该重构代码以将业务逻辑与 UI 逻辑分开。每个 .NET 版本都有已知的模式和实践,可以实现清晰的分离。我整理了一些工具和它们的用法链接供您查看。

工具:

开始调用

BeginInvoke用于在控件源自的线程上异步运行代码。这将允许在发起线程是 UI 线程的情况下发生 UI 操作。BackgroundWorker用这个来ReportProgress。这将允许 UI 在发生长时间运行的操作时保持响应。

这不应该直接嵌入到业务逻辑中。但是,它可用于将消息中继回 UI 线程。

看:

后台工作者

  • BackgroundWorker将在单独的线程上运行工作,并且具有事件驱动的进程(.NET 2.0+)。

BackgroundWorker是一个事件驱动的控件,它将在另一个线程上执行代码。它具有内置功能,可以使用ReportProgress.

在幕后,允许有效分离业务逻辑的BackgroundWorker用途Control.BeginInvokeReportProgress

看:

调度员

  • 可以将Dispatcher操作中继到 UI 线程(.NET 3.0+);

Dispatcher为 WPF 添加,但仍可在 WinForms 中使用(尽管不太理想)。will的Dispatcher功能与它相同BeginInvoke,它可以同步或异步运行。

看:

任务

  • 该类Task(T)使从 UI 线程中交织逻辑变得简单。(.NET 4.0+、.NET 3.5+ 和 TPL 包)。

添加了任务并行库以提供一组并行性和并发性的抽象。Task是消息驱动的,允许封装非阻塞操作。这也是 .NET 4.5 async/await模式的基础。

Task用于流式操作,以便它们可以链接在一起并产生结果。这比 更精简,BackgroundWorker并且可以更好地组合操作。这也使得实现生产者-消费者场景更简单。

看:

于 2013-07-08T16:04:54.890 回答
1

@Servy 建议不要混合 UI 和逻辑,而是先执行逻辑,然后将结果应用到 UI。虽然这不符合最初的目的,但它似乎是解决我的问题的最简单方法。(带有进度条的表单仅在执行逻辑时可见,但现在在更新 UI 时可见。) UI 更新将在 aprox 中完成。一秒钟,因此由于时间很短,因此进度条最终并不是真正需要的。

对于那些在加载 UI 时仍然需要进度条的人,在这个问题下给出了一些很好的答案/解决方案。

于 2013-07-08T16:44:35.390 回答