Tre*_*son 3 .net c# multithreading doevents winforms
我一直在尝试创建一个写入数据库的任务,而不会阻塞UI线程。我遇到的最大问题是等待该过程完成而不会发生阻塞。
我一直在尝试避免使用DoEvents(尽管此程序现在经常使用它,但我希望在前进时不再使用它)。
我试图创建要在第二个线程上运行的进程,并等待它完成以及使用BackgroundWorker。
我遇到的问题不是让代码在其他线程中运行,而是试图找到一种方法来等待它完成。
基本上,现在我要执行以下操作:
BackgroundWorker所以我可以使用ReportProgressBackgroundWorkerBackgroundWorker完成。对于线程,我等待IsAlive变为false,对于BackgroundWorker,我切换一个布尔变量。问题出在#4中。
在没有代码的情况下执行while循环,或者Thread.Sleep(0)阻塞UI(Thread.Sleep(0)使程序也占用程序资源的100%)
所以我做:
while (!thread.IsAlive)
Thread.Sleep(1);
Run Code Online (Sandbox Code Playgroud)
-要么-
while (bProcessIsRunning)
Thread.Sleep(1);
Run Code Online (Sandbox Code Playgroud)
这会阻塞用户界面。
如果在此调用Application.DoEvents(),则UI会更新(尽管它是可单击的,所以在此过程运行时,我必须禁用整个表单)。
如果我同步运行该过程,那么我仍然需要创建某种方式来更新UI(在我看来,是一个DoEvents调用),这样它就不会被锁定。
我究竟做错了什么?
首先,为什么要避免DoEvents()?
其次,您使用的是相互矛盾的术语。
等待==阻止
你说你不希望阻止UI线程,但你做的要等待任务完成。这些是互斥状态。如果您正在等待完成某件事,那么就阻塞了线程。
如果您希望UI实际上是可用的(不被阻止),那么您就不必等待任务完成。只需注册一个事件处理程序即可在完成时触发。例如,使用BackgroundWorker处理RunWorkerCompleted事件。对于Task,您可以使用延续将回调分配给您的主线程。
但是似乎您只希望更新UI,而不是可用的。通常,只有在您希望进度条或其他UI动画继续移动时才有意义。在这种情况下,我将打开一个模式对话框,启动我的任务,然后等待,是的,调用DoEvents()。
var dialog = new MessageBoxFormWithNoButtons("Please wait while I flip the jiggamawizzer");
dialog.Shown += (_, __) =>
{
var task = Task.Factory.StartNew(() => WriteToDatabase(), TaskCreationOptions.LongRunning);
while (!task.Wait(50)) // wait for 50 milliseconds (make shorter for smoother UI animation)
Application.DoEvents(); // allow UI to look alive
dialog.Close();
}
dialog.ShowDialog();
Run Code Online (Sandbox Code Playgroud)
模态对话框阻止用户执行任何操作,但是由于DoEvents()每秒被调用20次(或更多次),因此任何动画仍然可以使用。
(您可能想为不同的任务完成状态添加特殊处理,但这是不合时宜的。)