winforms 在C#中执行任何其他操作时窗体不响应

jpfvwuh4  于 2022-12-23  发布在  C#
关注(0)|答案(5)|浏览(248)

我有一个带有进度条的表单(使用VS2010在C#中开发)。这是一种秒表表单,我在其中填充进度条,比如说10秒...随着时间的推移,进度条相应地填充...意味着5秒后,进度条将填充50%等等...
我使用了for循环来执行这个操作:-

for(int count=0;count<200;count++)
{
   progbar.performstep();
   progbar.update();
   update();
   Thread.Sleep(50);
}

我已经使用了线程。睡眠50毫秒,使进度条更新顺利。为1秒,它递增的步骤。
问题是,如果我执行任何其他操作,如移动此表单,甚至单击桌面上的另一个图标,会使此表单“无响应”....但它会执行操作,并在10秒结束时恢复其状态,并显示弹出窗口,指示10秒已过,进度条已满。
谢谢你的帮助,抱歉用了这么复杂的语言。
问候你Swanand

更新:我在下面答案的帮助下解决了这个问题....我了解到的一个常见错误是忘记了“Applications.DoEvents()“沿着“update()“....如果你输入这一行,被“挂”的机会就小多了!

vybvopom

vybvopom1#

您正在UI线程上执行一个长时间运行的操作,这意味着UI“消息循环”(负责处理用户输入和更新屏幕等事件)没有机会运行。
您应该在另一个线程上执行长时间运行的操作(无论是您自己创建的线程还是后台线程),并使用BackgroundWorker轻松更新进度条,或者在需要更新UI时使用Control.Invoke/BeginInvoke马歇尔委托调用封送回UI线程。(您一定不要从错误的线程更新控件。
如果您唯一的UI交互是填充进度条,我建议使用BackgroundWorker
如果你不是真的在做“真正的”工作,只是在等待时间的流逝,你可以使用System.Windows.Forms.Timer来代替所有这些,然而。这将在UI线程上“滴答”,但不会在滴答之间阻塞UI线程。你应该只在你没有太多工作要做的时候使用它--如果它 * 真的 * 只是更新一个进度条,而不是(比如)处理文件等。请注意,您不应该依赖于计时器准确地“准时”触发-您可能应该根据观察到的时间而不是观察到的滴答数来设置进度条的位置。

omhiaaxx

omhiaaxx2#

你阻塞了UI线程,这意味着它没有处理诸如“paint”之类的事件。要正确地做到这一点,你应该使用类似BackgroundWorker的东西,并且只从progress事件更新UI。

using System;
using System.Windows.Forms;
using System.ComponentModel;
using System.Threading;

static class Program
{
    [STAThread]
    static void Main()
    {
        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);
        Application.Run(new MyForm());
    }
}

class MyForm : Form
{
    Button btn;
    BackgroundWorker worker;
    ProgressBar bar;
    public MyForm()
    {
        Controls.Add(btn = new Button { Text = "Click me" });
        btn.Click += new EventHandler(btn_Click);

        Controls.Add(bar = new ProgressBar { Dock = DockStyle.Bottom, Visible = false, Minimum = 0, Maximum = 100 });

        worker = new BackgroundWorker { WorkerReportsProgress = true };
        worker.ProgressChanged += new ProgressChangedEventHandler(worker_ProgressChanged);
        worker.DoWork += new DoWorkEventHandler(worker_DoWork);
        worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(worker_RunWorkerCompleted);
    }

    void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {
        bar.Visible = false;
        if (e.Error != null)
        {
            Text = e.Error.Message;
        }
        else if (e.Cancelled)
        {
            Text = "cancelled";
        }
        else
        {
            Text = e.Result == null ? "complete" : e.Result.ToString();
        }
        btn.Enabled = true;
    }

    void worker_DoWork(object sender, DoWorkEventArgs e)
    {
        for (int count = 0; count < 100; count++)
        {
            worker.ReportProgress(count);
            Thread.Sleep(50);
        }
    }

    void worker_ProgressChanged(object sender, ProgressChangedEventArgs e)
    {
        bar.Value = e.ProgressPercentage;
    }

    void btn_Click(object sender, EventArgs e)
    {
        bar.Value = 0;
        bar.Visible = true;
        btn.Enabled = false;
        worker.RunWorkerAsync();
    }
}
dy1byipe

dy1byipe3#

您正在阻塞主UI线程。您可以使用后台工作线程来执行此操作。您可以在MSDN中找到更多详细信息

uwopmtnx

uwopmtnx4#

如果你想运行你的代码,你应该把这个代码放在一个函数中,并用一个线程调用这个函数。

public static void fun1()
        {
            for (int i = 0; i <= 10; i++)
            {
                Console.Write("This is function1");
                Console.Write("\n");

            }

        }
  Thread firstthread = new Thread(new ThreadStart(fun1));

  firstthread.Start();
  firstthread.suspend();//whenever you want your current control to stop.

sleep(100)将停止整个上下文,而不是您想要的特定上下文。

7ivaypg9

7ivaypg95#

Marc建议的答案会有帮助。Lon运行操作会使你的应用程序崩溃或没有响应。我有一篇博客文章与后台工人类的使用有关。
http://midnightprogrammer.net/post/Using-Background-Worker-in-C.aspx

相关问题