【问题标题】:Best way to display a progress form while a method is executing code?在方法执行代码时显示进度表的最佳方式?
【发布时间】:2013-03-24 01:15:15
【问题描述】:

我有一个 WinForm 加载方法,它需要很长时间才能收集一些数据以显示给用户。

在执行此方法时,我会显示一个带有“Loading”字样的大字体表单。

但有时会出现此错误并且“正在加载”进度表没有关闭,然后最终我的整个应用程序将退出:

创建窗口句柄时出错。在 System.Windows.Forms.NativeWindow.CreateHandle(CreateParams cp)

当我在加载方法中执行代码时,有没有更好的方法来显示我的进度/加载表单?

这是我的代码:

//I launch a thread here so that way the Progress_form will display to the user
//while the Load method is still executing code.  I can not use .ShowDialog here
//or it will block.

//Progress_form displays the "Loading" form    
Thread t = new Thread(new ThreadStart(Progress_form));  

t.SetApartmentState(System.Threading.ApartmentState.STA);
t.IsBackground = true;
t.Start();

//This is where all the code is that gets the data from the database.  This could
//take upwards of 20+ seconds.

//Now I want to close the form because I am at the end of the Load Method                         

try
{
   //abort the Progress_form thread (close the form)
   t.Abort();
   //t.Interrupt();
}
catch (Exception)
{
}

【问题讨论】:

  • 也许这里有一些想法:stackoverflow.com/q/15566176/327083
  • 你应该换一种方式。在后台线程中执行加载工作并使用主 UI 线程显示某种进度条。
  • @VaibhavDesai - 如果耗时的操作涉及加载密集的 UI 对象,有时这在负载处理程序中是不可能的。在这种情况下,它必须由 UI 线程完成,因为它最终必须拥有这些对象。这就是为什么有些应用程序使用闪屏的原因。

标签: c# multithreading


【解决方案1】:

BackgroundWorker 是在不锁定 UI 线程的情况下执行长时间运行操作的好方法。

使用以下代码启动 BackgroundWorker 并显示加载表单。

// Configure a BackgroundWorker to perform your long running operation.
BackgroundWorker bg = new BackgroundWorker()
bg.DoWork += new DoWorkEventHandler(bg_DoWork);
bg.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bg_RunWorkerCompleted);

// Start the worker.
bg.RunWorkerAsync();

// Display the loading form.
loadingForm = new loadingForm();
loadingForm.ShowDialog();

这将导致在后台线程上执行以下方法。请注意,您不能从此线程操作 UI。尝试这样做会导致异常。

private void bg_DoWork(object sender, DoWorkEventArgs e)
{
    // Perform your long running operation here.
    // If you need to pass results on to the next
    // stage you can do so by assigning a value
    // to e.Result.
}

长时间运行的操作完成后,将在 UI 线程上调用此方法。您现在可以安全地更新任何 UI 控件。在您的示例中,您可能希望关闭加载表单。

private void bg_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
    // Retrieve the result pass from bg_DoWork() if any.
    // Note, you may need to cast it to the desired data type.
    object result = e.Result;

    // Close the loading form.
    loadingForm.Close();

    // Update any other UI controls that may need to be updated.
}

【讨论】:

    【解决方案2】:

    我已经在 .NET 4.0 上成功测试了这个。 (WinForms)我有理由确定这将在 .NET 4.0+ 上运行,并且应该是一个有用的代码 sn-p,可以在大多数需要在进程结束时关闭表单的项目中重用。

    private void SomeFormObject_Click(object sender, EventArgs e)
    {
        myWait = new YourProgressForm();//YourProgressForm is a WinForm Object
        myProcess = new Thread(doStuffOnThread);
        myProcess.Start();
        myWait.ShowDialog(this);
    }
    
    private void doStuffOnThread()
    {
        try
        {
            //....
            //What ever process you want to do here ....
            //....
    
            if (myWait.InvokeRequired) {
                myWait.BeginInvoke( (MethodInvoker) delegate() { closeWaitForm(); }  );
            }
            else
            {
                myWait.Close();//Fault tolerance this code should never be executed
            }
        }
        catch(Exception ex) {
            string exc = ex.Message;//Fault tolerance this code should never be executed
        }
    }
    
    private void closeWaitForm() {
        myWait.Close();
        MessageBox.Show("Your Process Is Complete");
    }
    

    【讨论】:

      【解决方案3】:

      我会将您在加载方法中的代码放入一个线程中。在表单的某处设置一个进度条,并在收集数据的代码的关键阶段增加它 - 但请注意不要在线程本身中执行此操作,即不要在单独的线程中篡改 ui 元素,您将需要使用委托来调用它们。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2012-10-02
        • 1970-01-01
        • 1970-01-01
        • 2012-03-02
        • 1970-01-01
        • 2011-01-05
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多