Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/306.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#progressbar未更新_C#_Wpf_Progress Bar_Ui Thread - Fatal编程技术网

c#progressbar未更新

c#progressbar未更新,c#,wpf,progress-bar,ui-thread,C#,Wpf,Progress Bar,Ui Thread,我有一个progressbar窗口,上面有一个progressbar和一个cancel按钮,我用它来报告文件I/O的进度。然而,progressbar窗口的UI线程和我的主窗口都挂起,尽管所有的工作都在backgroundworker中完成。progressbar与我的主窗口一样呈现,但在backgroundworker执行其操作时不会更新。 在主窗口构造函数的最末端调用以下代码: iCountLogLinesProgressBar = new ProgressBarWindow(); iCou

我有一个progressbar窗口,上面有一个progressbar和一个cancel按钮,我用它来报告文件I/O的进度。然而,progressbar窗口的UI线程和我的主窗口都挂起,尽管所有的工作都在backgroundworker中完成。progressbar与我的主窗口一样呈现,但在backgroundworker执行其操作时不会更新。 在主窗口构造函数的最末端调用以下代码:

iCountLogLinesProgressBar = new ProgressBarWindow();
iCountLogLinesProgressBar.cancelButton.Click += EventCountLogLinesProgressBarCancelButtonClicked;
iCountLogLinesProgressBar.Show();

iCountLogRecords = new BackgroundWorker();
iCountLogRecords.DoWork += EventCountLogLinesDoWork;
iCountLogRecords.ProgressChanged += EventCountLogLinesProgressChanged;
iCountLogRecords.RunWorkerCompleted += EventCountLogLinesRunWorkerCompleted;
iCountLogRecords.WorkerReportsProgress = true;
iCountLogRecords.WorkerSupportsCancellation = true;
iCountLogRecords.RunWorkerAsync(new BinaryReader(File.Open(iMainLogFilename, FileMode.Open, FileAccess.Read)));
EventCountLogLinesProgressChanged()如下所示:

private void EventCountLogLinesProgressChanged(object sender, ProgressChangedEventArgs e)
{
    iCountLogLinesProgressBar.Value = e.ProgressPercentage;
}
下面是ProgressBarWindow的一个缩短版本(其余只是几个setter):

我曾尝试将值设置程序行包装在dispatcher.invoke委托中,但这会导致堆栈溢出(在UI线程中backgroundworker调用ProgressChanged时,我不必使用dispatcher.invoke行,对吧?)。我已经查过msdn和谷歌,但我似乎找不到其他有这个问题的人


编辑抱歉,我没有意识到我的简化代码阻止了UI线程,尽管使用了backgroundworker,但我得到了完全相同的行为,因此我错误地认为它们是等效的。我应该提到我使用的是backgroundworker:P

您正在阻止UI线程,因此在循环完成之前它不会重新呈现UI

将后台处理移到单独的线程中,并使用适当的
调度程序
调用(或
BackgroundWorker
)将UI更新调用封送回UI线程

如果你的进度条实际上只是一个计时器,你可以使用
timer
类来更新它

编辑:好的,现在你已经更改了代码,我觉得没问题。它应该是线程安全的,因为您只是在UI线程上更改UI。你的背景工作人员肯定会定期报告进度吗?

听Jon Skeet说,
或者您有时可以调用Application.DoEvents()在同一线程中进行所有UI更新。

-1:直接调用Application.DoEvents是不好的做法。它会导致UI线程递归地进入其消息抽取过程,这可能会导致一些严重的问题。正确编写应用程序并允许UI线程正常地发送消息要好得多。这取决于规模。例如,如果它是一个执行简单更新的小型桌面应用程序,您可以花15分钟在一个线程中使用Application.DoEvents()编写它,或者将其复杂化,将简单方法调用更改为方法调用。我只是列举了另外一个选项,指定Jon Skeet的选项在大多数情况下更好。所以我对列举一个选项投了反对票。很好。我认为,以当前的形式,您的答案可能会导致阅读该问题的开发人员养成坏习惯,使用Application.DoEvents for作为解决UI更新问题的银弹(很多人都是这样做的)。我只是永远不会使用Application.DoEvents来达到所讨论的目的。是的,在这种情况下,听Jon Skeet的建议似乎是个好建议,而你刚才又列举了一个选项,但在我看来,这是个坏选项。但这只是一个人的意见,这反映在你的答案的分数上。对不起。我只是习惯了-1代表一个糟糕的,错误的答案。我只是不知道列举一个有效的(但远不是最好的)选项也符合这个条件。我看到许多开发人员在这个线程和其他线程上抛出“调用DoEvents是不好的做法;不要这样做,正确地做”类型的评论。他们从不解释为什么这是一种不好的做法,也很少提供实际的解决方案。DoEvents通常适用于男性,这就是他们这么做的原因。也许让这样简单的东西真正起作用并不难。我上面有一个backgroundworker,但我也需要一个dispatcher.invoke调用我的值设置器吗?@teflon19:不,你不需要做任何其他事情,只需要确保在后台工作程序中报告进度。我只在进度发生变化时报告进度,太多的progresschanged事件减慢了进度,但UI仍然冻结。ProgressBarWindow的UI线程会受到backgroundworker的影响,这有什么原因吗?@teflon19:如果你经常更新UI,以至于它实际上没有机会重新绘制,那肯定是个问题。为什么不对其进行过滤,以便仅当(比如)四舍五入为整数时百分比发生实际变化时才报告进度。这样你最多可以有100个更新。是的,我刚刚发现我的UI只收到一个进度更改报告(进度==100%)。由于某些原因,它只更新一次。我要仔细看看。看起来上面的问题有点像是在转移视线。无论如何,谢谢你的帮助!
public partial class ProgressBarWindow : Window
{
    public ProgressBarWindow()
    {
        InitializeComponent();
        this.progressBar.Value = this.progressBar.Minimum = 0;
        this.progressBar.Maximum = 100;
    }

    public double Value
    {
        get
        {
            return progressBar.Value;
        }
        set
        {
            this.progressBar.Value = value;
        }
    }
}