C# 在方法执行代码时显示进度表的最佳方式?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/15769276/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-10 17:53:16  来源:igfitidea点击:

Best way to display a progress form while a method is executing code?

c#multithreading

提问by fraXis

I have a WinForm load method that takes a long time to gather some data to display to the user.

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

I display a form with a large font with the word "Loading" while this method is executing.

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

However sometimes this error comes up and the "Loading" progress form does not close and then eventually my whole application will just exit:

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

Error creating window handle. at System.Windows.Forms.NativeWindow.CreateHandle(CreateParams cp)

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

Is there a better way to display my progress/loading form while I am executing code in the load method?

This is my code:

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

这是我的代码:

//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)
{
}

采纳答案by Timothy Schoonover

A BackgroundWorkeris a great way to perform a long running operation without locking the UI thread.

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

Use the following code to start a BackgroundWorker and display a loading form.

使用以下代码启动 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();

This will cause the following method to be executed on a background thread. Note that you cannot manipulate the UI from this thread. Attempting to do so will result in an exception.

这将导致在后台线程上执行以下方法。请注意,您无法从该线程操作 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.
}

When the long running operation completes, this method will be called on the UI thread. You can now safely update any UI controls. In your example, you would want to close the loading form.

当长时间运行的操作完成时,将在 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.
}

回答by Crwydryn

I would take the code that you have in your load method and place that into a thread. Setup a progress bar somewhere on your form and increment it at key stages in the code that's gathering the data - be careful not to do this in the thread itself though, i.e. don't tamper with ui elements in a separate thread, you'll need to invoke them using a delegate.

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

回答by user2288580

Ive successfully tested this on .NET 4.0. (WinForms) I'm reasonably certain that this will work on .NET 4.0+ and should be a useful code snippet to reuse in most of your projects that require closing forms at the end of a process.

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

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");
}