首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >Winforms进度栏不更新(C#)

Winforms进度栏不更新(C#)
EN

Stack Overflow用户
提问于 2009-07-01 11:52:48
回答 4查看 37.5K关注 0票数 15

在我的程序中,C# + winforms。我有进度条和列表视图。

通过一种方法,我执行了一些操作&然后在Listview中更新数据。添加的记录数是我为ProgressBar.value属性设置的值。我想要的是,根据进度条的值,它应该显示它的进度。但是,进度条没有更新。只有在方法执行结束时,进度条才会显示整个进度,即100%

有人能在这方面帮助我吗?

谢谢,阿米特

EN

回答 4

Stack Overflow用户

发布于 2009-07-01 11:56:07

这听起来像是你阻塞了UI线程--也就是说,你还没有释放系统来做任何绘画。

一个老生常谈的答案是将Application.DoEvents()注入到你的代码中--但这是有风险的,并且在可重入性等方面存在问题;而且它只是有点老生常谈。

一个更好的选择可能是在BackgroundWorker上进行处理,定期切换到UI线程来更新内容(Control.Invoke) -但如果您正在向ListView添加大量项,这可能会很棘手。

完整的示例(尽管您可能希望批量更新UI -而不是一次一行):

代码语言:javascript
复制
using System;
using System.ComponentModel;
using System.Threading;
using System.Windows.Forms;

class MyForm : Form
{
    BackgroundWorker worker;
    ListView list;
    Button btn;
    ProgressBar bar;
    public MyForm()
    {
        Text = "Loader";
        worker = new BackgroundWorker();
        worker.WorkerReportsProgress = true;
        worker.ProgressChanged += worker_ProgressChanged;
        worker.DoWork += worker_DoWork;
        worker.RunWorkerCompleted += worker_RunWorkerCompleted;
        list = new ListView();
        list.Dock = DockStyle.Fill;
        Controls.Add(list);
        btn = new Button();
        btn.Text = "Load";
        btn.Dock = DockStyle.Bottom;
        Controls.Add(btn);
        btn.Click += btn_Click;
        bar = new ProgressBar();
        bar.Dock = DockStyle.Top;
        Controls.Add(bar);
    }

    void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {
        btn.Enabled = true;
    }

    void btn_Click(object sender, EventArgs e)
    {
        worker.RunWorkerAsync();
        btn.Enabled = false;
    }


    void worker_DoWork(object sender, DoWorkEventArgs e)
    {
        for (int i = 0; i < 100; i++)
        {
            string newRow = "Row " + i.ToString();
            worker.ReportProgress(i, newRow);
            Thread.Sleep(100);
        }
    }

    void worker_ProgressChanged(object sender, ProgressChangedEventArgs e)
    {
        list.Items.Add((string)e.UserState);
        bar.Value = e.ProgressPercentage;
    }

    [STAThread]
    static void Main()
    {
        Application.EnableVisualStyles();
        Application.Run(new MyForm());
    }
}
票数 27
EN

Stack Overflow用户

发布于 2009-07-01 12:21:57

真的很抱歉朋友们

实际上,我给ProgressBar.value字段赋值,但没有使用update()方法。我使用了它&我的问题得到了解决。

感谢所有人的回复

票数 10
EN

Stack Overflow用户

发布于 2009-07-01 12:13:19

正如Marc所说,您希望确保您创建了一个新线程来执行您的长时间运行的计算。这样,每当您更改完成百分比时,用户界面线程(必须执行所有屏幕更新的线程)就可以重新绘制进度条。

需要注意的是,只有UI线程才能更新界面。因此,一旦您在单独的线程上运行,就必须经历额外的循环,以确保UI更改在UI线程上得到处理。如果你不确定你在哪个线程上运行,你可以检查InvokeRequired的值(如果你的类是一个System.Windows.Form),看看你是否真的在UI线程中。

若要在UI线程上处理命令,请使用Control.Invoke()函数确保在正在使用的控件的UI线程上处理更新。

在我下面的示例代码中,我创建了一个委托函数类型,并提前声明了被调用的函数……我没有用任何很酷的Lamba3.5函数来做这件事,但我打赌你可以用一个C#表达式来做同样的事情。

代码语言:javascript
复制
 private void bCreateInvoices_Click(object sender, EventArgs e)
    {
        BackgroundWorker worker = new BackgroundWorker();
        worker.DoWork += new DoWorkEventHandler(CreateInvoices);
        worker.RunWorkerAsync(this);
    }

 // Here is the long running function that needs to update the progress bar
 public void CreateInvoices(object sernder, DoWorkEventArgs e)
    {
        int totalChecked = CountCheckedServiceOrders();
        int totalCompleted = 0;

        foreach (...data to process...) {
            totalCompleted++;
            if (InvokeRequired) {
               Invoke(new Change(OnChange), "status text", 
                        totalCompleted, totalChecked);                
            }
        }
    }

    // this code updates the status while a background thread works
    private delegate void Change(string status, int complete, int total);
    private void OnChange(string status, int complete, int total)
    {
        if (status == null) {
            progressBar.Visible = false;
            lStatus.Text = "Task complete";
            progressBar.Value = 0;
        } else {
            progressBar.Visible = true;
            progressBar.Minimum = 0;
            progressBar.Maximum = total;
            progressBar.Value = complete;
            lStatus.Text = status;
        }

    }

有关更多信息,请查看MSDN Control.InvokeRequired manual pageMSDN Control.Invoke manual page

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/1068720

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档