Правильный способ реализовать прогрессбар в C # - PullRequest
4 голосов
/ 01 июня 2011

Я изучаю winforms, и я поставил перед собой простую цель - сделать прогрессбар, который идет от пустого до полного.Вот моя попытка деформирования:

public partial class Form1 : Form
{
    static BackgroundWorker bw = new BackgroundWorker();

    public Form1()
    {
        InitializeComponent();
        bw.DoWork += bw_DoWork;
        bw.RunWorkerAsync();
    }

    void bw_DoWork(object sender, DoWorkEventArgs e)
    {
        for(int i=0; i<100; ++i)
        {
            progressBar1.PerformStep();
            Thread.Sleep(10);
        }
    }
}

Я почти уверен, что Thread.Sleep() предосудительно.Как мне избежать этого здесь?

Ответы [ 3 ]

7 голосов
/ 01 июня 2011

Вы уже делаете это почти правильно. BackgroundWorker имеет встроенный механизм для сообщения о прогрессе уже.

public Form1()
{
    bw1.WorkerReportsProgress = true;
    bw1.ProgressChanged += bw1_ProgressChanged;
    bw1.DoWork += bw1_DoWork;

    bw1.RunWorkerAsync();
}

private void bw1_DoWork(object sender, DoWorkEventArgs e)
{
    var worker = sender as BackgroundWorker;

    while (workNotDone)
    {
        //Do whatever work
        worker.ReportProgress(CalculateProgressDonePercentage());
    }
}

private void bw1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
    //This is called on GUI/main thread, so you can access the controls properly
    progressBar.Value = e.ProgressPercentage;
}

Если, конечно, вы просто не пытаетесь анимировать индикатор выполнения, фактически не сообщая о каком-либо прогрессе, в этом случае вам, вероятно, следует просто использовать тип Marquee, который автоматически прокручивает индикатор выполнения, ничего не делая. Или просто используйте фоновый поток с Thread.Sleep().

3 голосов
/ 01 июня 2011

В фоновом потоке нет ничего плохого в вызове Thread.Sleep.
Если это заполнитель, вы можете смело заменить его фактической работой.

Однако вы не можете манипулировать ProgressBar (или любым другим элементом управления) напрямую из фонового потока.
Вместо этого вы должны использовать встроенные функции прогресса BackgroundWorker для управления индикатором выполнения.

Если вы просто пытаетесь оживить бессмысленный индикатор прогресса, вы должны использовать WinForms Timer вместо BackgroundWorker.

1 голос
/ 01 июня 2011

Если вы просто хотите протестировать обновление пользовательского интерфейса при выполнении трудоемкой задачи, Thread.Sleep в порядке.Для нетривиальных программ вы всегда найдете здесь какую-то задачу.

Однако не следует обновлять индикатор выполнения непосредственно внутри BackgroundWorker.DoWork, поскольку Windows требует, чтобы обновление пользовательского интерфейса вызывалось в пользовательском интерфейсе.нить, а не фон.Вместо этого вызовите метод BackgroundWorker.ReportProgress.Всегда обновляйте пользовательский интерфейс внутри события BackgroundWorker.ProgressChanged.

Вы можете увидеть пример здесь: http://msdn.microsoft.com/en-us/library/cc221403(v=vs.95).aspx

...