Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/266.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 进度条是否仅在工作完成后显示?_C#_Winforms_Progress Bar - Fatal编程技术网

C# 进度条是否仅在工作完成后显示?

C# 进度条是否仅在工作完成后显示?,c#,winforms,progress-bar,C#,Winforms,Progress Bar,我试图在表单上显示一个进度条,但由于某些原因,表单在流程结束之前实际上不可见,并且在流程结束时关闭,或者换句话说,表单只打开一瞬间。如何使表单在流程开始时显示 注意:我的代码可能不是100%正确,出于保密原因,我只是想让它不同于我自己的代码 public void SpawnPizzaProgressBarForm(object sender, EventArgs e) { FormPizzaProgressBar Form = new FormPizzaProgressBar();

我试图在表单上显示一个进度条,但由于某些原因,表单在流程结束之前实际上不可见,并且在流程结束时关闭,或者换句话说,表单只打开一瞬间。如何使表单在流程开始时显示

注意:我的代码可能不是100%正确,出于保密原因,我只是想让它不同于我自己的代码

public void SpawnPizzaProgressBarForm(object sender, EventArgs e)
{
    FormPizzaProgressBar Form = new FormPizzaProgressBar();
    Form.ShowDialog();
}
...
public void ProgressBarForm_Load(object sender, EventArgs e)
{
    Pizza = new Pizza();
    Pizza.Eat(PizzaEatingProgressBar);
    this.Close();
}
...
public void Eat(ProgressBar PizzaEatingProgressBar)
{
    foreach(var Slice in Pizza)
    {
        Slice.Clear(); //
        PizzaEatingProgressBar.Value = (Slice.Index / Pizza.Count())*100
    }
}

这看起来像是一个紧密的循环-您需要使用BackgroundWorker将工作放在后台线程上,或者通过调用Application.DoEvents处理消息队列(其中包括paint命令)来欺骗并给UI时间进行更新


如果循环太紧或工作太繁重,UI将在很大程度上阻塞直到完成,即使UI更改相互混合。

您需要使用线程来更新UI,而BackgroundWorker将处理您的实际流程。在开始之前,请先从Estemable Jon Skeet中签出。

之所以会出现这种情况,是因为您在中完成了所有处理。在第一次显示窗体之前调用此函数

在事件处理程序中,您会阻止表单实际显示,因为事件处理程序必须在处理任何其他内容之前完成

您要做的是使用实例来执行您的工作。这要求您执行以下操作:

如果默认值为false,则将设置为true 订阅 在DoWork事件处理程序中,调用以报告进度 订阅,这是更新进度条的地方。这也是调用前面提到的ReportProgrss方法时触发的事件htat 订阅,完成后您将在此处关闭表单 调用以启动异步操作 你有一些问题在这里,你有你的比萨饼类紧密耦合到进度条。这不是个好主意。相反,您应该触发一个事件来指示进度已更改,然后从Pizza实例的事件处理程序调用ProgressChanged事件

我已经删除了Eat方法的代码,并将其封装在表单中,以向您展示如何使用BackgroundWorker类的示例,但理想的解决方案是公开一个事件,以指示比萨饼消费量何时发生变化

还请注意,您应该重写,以便在处理窗体时正确处理BackgroundWorker实例

下面是示例的内容:

public void SpawnPizzaProgressBarForm(object sender, EventArgs e)
{
    FormPizzaProgressBar Form = new FormPizzaProgressBar();
    Form.ShowDialog();
}

...

BackgroundWorker worker = new BackgroundWorker();

public void ProgressBarForm_Load(object sender, EventArgs e)
{
    // Initialize the background worker.
    worker = new BackgroundWorker();

    // Indicate that the worker supports progress.
    worker.WorkerSupportsProgress = true;

    // Subscribe to the DoWork event.
    worker.DoWork += (s, e) => {
        // Create the pizza instance.
        Pizza = new Pizza();

        // Process the slices.
        foreach (var Slice in Pizza)
        {
            // Clear the slice.
            Slice.Clear();

            // Report the progress.
            worker.ReportProgress(Slice.Index / Pizza.Count() * 100);
        }
    };

    // Subscribe to the ProgressChanged event.
    worker.ProgressChanged = (s, e) => {
        // Update the progress bar.
        PizzaEatingProgressBar.Value = e.ProgressPercentage;
    };

    // Subscribe to the RunWorkerCompleted event.
    worker.RunWorkerCompleted = (s, e) => {
        // Close the dislog.
        this.Close();
    };
}

// Must override to properly dispose of the background worker.
protected override void Dispose(bool disposing)
{
    // Call the base.
    base.Disposing(disposing);

    // Dispose of the background worker if disposing is true.
    if (disposing) worker.Dispose();
}

Winforms基于Windows API,它不会更新GUI元素,除非创建GUI元素的线程已启动。WinForms在线程上调用了ProgressForm_Load方法,它必须在该线程上泵送消息,以便更新GUI元素。在Eat中操作期间,您没有泵送消息队列。因此,如果GUI元素不更新,您将看不到进度条的更改

最简单的解决方案是在Eat方法中定期调用Application.DoEvents。更好的方法是在不同的线程上执行长操作,在该操作期间显示沙漏,并使用GUI更新的调用样式定期通知进度条进行更新。除了创建GUI元素的线程之外,您不能直接从其他线程调用大多数GUI元素的方法

 PizzaEatingProgressBar.Value = (Slice.Index / Pizza.Count())*100
如果Slice.Index为整数,则不起作用。您需要将其转换为双精度以获得浮点除法。例如:

 PizzaEatingProgressBar.Value = (int)((double)Slice.Index / Pizza.Count) * 100);
或者像这样做:

 PizzaEatingProgressBar.Value = (Slice.Index * 100) / Pizza.Count;

这确保除法不能像原始表达式那样截断为0。与大家的建议相反,当您更改Value属性时,ProgressBar会自行绘制。尽管您的窗口仍然处于紧张状态。

+1为了发现事件,我没有注意到这一点,只是假设UI线程阻塞会导致绘制问题。这是一个很好的答案,更像是一篇信息帖子。非常感谢。