对话框如何在不阻塞主线程的情况下防止代码执行

本文关键字:情况下 执行 代码 线程 对话框 | 更新日期: 2023-09-27 18:08:11

在c# WinForms中,如果你打开一个对话框,它不会在显示对话框之后继续执行代码,直到你点击ok。这显然是正在发生的事情。但是,当对话框打开时,主线程仍然可以执行代码。因此,对话框并没有阻塞主线程,但它阻塞了后续代码的特定范围。

我很好奇这到底是怎么回事。你能/如何实现这样的东西?(我不想这样做,我只是意识到我不完全理解对话框如何在不阻塞线程执行的情况下工作。)

考虑这个带有两个按钮和一个标签的示例代码和项目。标签显示计数器的值。计时器每500毫秒增加一次计数器。其中一个按钮打开一个对话框。另一个运行调用Thread的循环。一秒钟睡十次。您将注意到标签计数器在对话框打开时增加,而线程打开时增加。Sleep会阻塞所有计时器的执行,直到完成。

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Threading;
namespace MainThreadPauser
{
    public partial class Form1 : Form
    {
        int counter = 0;
        public Form1()
        {
            InitializeComponent();
            System.Windows.Forms.Timer t = new System.Windows.Forms.Timer();
            t.Interval = 500;
            t.Enabled = true;
            t.Tick += new EventHandler(t_Tick);
            t.Start();
        }
        void t_Tick(object sender, EventArgs e)
        {
            BeginInvoke((Action)(() => {
                AddToCounter();
            }));
        }
        private void button1_Click(object sender, EventArgs e)
        {
            MyDialog dlg = new MyDialog();
            dlg.ShowDialog(this);
            AddToCounter(5000);
        }
        private void AddToCounter(int value = 1)
        {
            counter += value;
            label1.Text = counter.ToString();
        }
        private void button2_Click(object sender, EventArgs e)
        {
            for (int x = 0; x < 10; x++)
            {
                Thread.Sleep(1000);
            }
        }
    }
}

对话框如何在不阻塞主线程的情况下防止代码执行

总之:

你的gui线程运行一个messagepump,它处理点击/移动/键等消息。

当你打开一个模态对话框时,消息对话框会在对话框(while loop)中运行一个'new' messagepump/loop,所以所有的窗口消息都会被处理,但是它会阻塞当前方法,在那里show对话框被调用,直到你关闭对话框。这就是为什么计时器(它们在windowmessages上工作)和重新绘制窗口仍然有效。这个对话框会禁用你的窗口,所以你不能传递这个对话框。