0

基本上,我有一个类,里面有一个函数,它计算文本文件中的所有行。

我需要它来更新 Form1 中的每一行的进度条。我努力了:

public static void rfile(string f)
{
    string[] lines = File.ReadAllLines(f);
    Form1 form = new Form1();
    foreach (string l in lines)
    {
        form.increaseProg();
    }
}

表格.cs

public void increaseProg()
{
    progressBar.Value++;
    System.Threading.Thread.Sleep(1000);
    progressBar.Refresh();
}

但这似乎根本没有增加进度条。

4

3 回答 3

1

您可以利用Progress该类在长时间运行的操作期间对所有相关人员轻松更新 UI。在您的表单中创建Progress类,并指出当它获得进度时它应该如何更新 UI。然后将该对象提供给将要进行长期工作的另一个类:

private void button1_Click(object sender, EventArgs args)
{
    Progress<int> progress = new Progress<int>();
    progress.ProgressChanged += (p, value) => progressbar1.Value = value;
    Task.Run(() => SomeOtherClass.DoWork("c:/temp.txt", progress));
}

长时间运行的工作当然是在另一个线程中完成的,以避免阻塞 UI。该类Progress将为我们将事件编组ProgressChanged到 UI 线程,因此我们不需要考虑它。

现在对于工人,我们只需要在需要时报告进度:

public class SomeOtherClass
{
    public static void DoWork(string filepath, IProgress<int> progress)
    {
        int currentProgress = 0;
        foreach (var line in File.ReadLines(filepath))
        {
            DoSomethingWithLine();
            currentProgress++;
            progress.Report(currentProgress);
        }
    }
}

请注意,这种方法的另一个优点是SomeOtherClass不需要了解有关表单的任何信息。IProgress任何可以提供对象的人都可以调用它。如果您有其他表单需要调用该方法,则根本不需要更改它。这也意味着,如果一个开发人员正在编写表单,而另一个开发人员正在编写长期运行的流程,他们只需要就DoWork方法的签名达成一致;从那时起,UI 人员可以完成所有的 UI 工作,而非 UI 人员可以完成所有非 UI 工作,他们无需担心其他人在做什么。

至于为什么您的代码不起作用,问题是您的工作方法没有访问正在显示的表单的实例,您正在创建一个全新的表单,修改它的进度条,从不向任何人显示,然后扔掉。

于 2013-11-04T15:20:18.350 回答
0
using System.Windows.Threading;
Dispatcher.CurrentDispatcher.Invoke(new System.Action(() => ProgressBar1.Value = value));

您有时可以在做其他工作的同时使用上面的代码来更新 UI。不过,您需要一些方法来以数字方式跟踪进度。

如前所述,由于您将主线程与处理捆绑在一起,因此您无法在同一线程上更新 UI。上面的内容节省了一小部分时间来执行此操作。唯一的其他方法是后台工作人员,尽管对于您的情况来说这可能是矫枉过正。

编辑(在单独的表单上显示)
您是否将进度条上的修饰符设置为公开?该解决方案可以很好地在单独的窗口中显示进度,并且可以正确更新。

    private void button1_Click(object sender, EventArgs e)
    {
        Form2 f2 = new Form2();
        f2.progressBar1.Maximum = 1000;
        f2.Show();
        for(int i = 0; i < 1000; i++)
        {
            Thread.Sleep(10);
            f2.progressBar1.Value++;
        }
    }

请注意,进度窗口的 UI 将被锁定,直到底层进程完成。我刚刚对此进行了测试,它工作正常。

更新同一表单上的进度,但来自不同的类
您需要传递进度条的引用,以便您的方法知道它正在更新什么。

}
    private void button1_Click(object sender, EventArgs e)
    {
        Class1 c = new Class1();
        progressBar1.Maximum = 1000;
        for(int i = 0; i < 1000; i++)
        {
            Thread.Sleep(10);
            c.IncreaseProgress(progressBar1);
        }
    }
}

class Class1
{
    public void IncreaseProgress(ProgressBar p)
    {
        p.Value++;
    }
}

不过,上述两种方法都会在更新时锁定 UI。使用 BackgroundWorker 来避免这种情况。不过,此解决方案在快速而肮脏的实用程序中运行良好。

于 2013-11-04T13:45:21.653 回答
0

这是因为您正在阅读这些行,并且在更新进度条时,UI 不会像您想象的那样完全刷新。你需要做的,因为它有时可以工作,是做一个 progressBar.Refresh() (我不记得进度条是否有刷新功能),所以它可以在工作时更新表单视觉效果(特别是进度条)通过线条的方式。基本上,它“太快”会导致更新延迟。

进度条正在更新,您只是看不到刷新发生。一种方法是让它成为多线程的,但这对于读取行和更新 UI 来说是多余的。

不仅如此,您的代码基本上不显示 UI ...它正在更新,并且不显示 UI,您需要 Show() 表单并对其执行更新。您实例化了表单,但实际上并没有显示它。

于 2013-11-04T13:32:48.127 回答