主线程忙时连续更新UI

Rob*_*bin 1 .net c# multithreading winforms

我想在我的MainForm正在进行一些与数据库相关的工作时显示带有Progressbar的新表单.我已经读过你不想将UI传递给新的线程,所以我想知道解决这个问题的最佳解决方案是什么?

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

任何建议,将不胜感激!

编辑

澄清我实际想知道的事情:

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

... Content = DatabaseClass.LoadContent();
ApplyContentToUI(Content);
Run Code Online (Sandbox Code Playgroud)

我想做的是以下内容:

//Show a form here with a progressbar
... Content = DatabaseClass.LoadContent();
ApplyContentToUI(Content);
//Close the form here
Run Code Online (Sandbox Code Playgroud)

但是,因为执行ApplyContentToUI的时间是aprox.1秒我决定做以下事情:

//Show a form here with a progressbar
... Content = DatabaseClass.LoadContent();
//Close the form here
ApplyContentToUI(Content);
Run Code Online (Sandbox Code Playgroud)

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

Dus*_*gen 9

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

假.

建议:

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

工具:

的BeginInvoke

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

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

看到:

的BackgroundWorker

  • BackgroundWorker 将在一个单独的线程上运行,它具有事件驱动的进展(.NET 2.0+).

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

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

看到:

调度员

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

Dispatcher是为WPF添加的,但它仍然可以在WinForms中使用(尽管它不太理想).在Dispatcher以同样的方式将功能BeginInvoke,它可以同时运行同步或异步.

看到:

任务

  • Task(T)类简化了交织逻辑关闭UI线程.(.NET 4.0 +,带有TPL包的.NET 3.5+).

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

Task用于流操作,以便它们可以链接在一起并产生结果.这比BackgroundWorker它更简化,并且它允许更好的操作组合.这也使得实施生产者 - 消费者情景更加简单.

看到:

  • 1)这并没有真正解释OP*如何*使用这些技术来解决他的问题.提到它们实际上是一个评论,而不是一个答案.2)这不会解决OP正在将其UI逻辑与其业务逻辑混合的事实; 事实上,它鼓励他们更多地混合它.3)即使你*可以*在winforms中使用Dispatcher,它也不是一个合适的练习. (4认同)