WinForms ilerleme çubuğu nasıl kullanılır?


101

Harici kitaplıkta gerçekleştirilen hesaplamaların ilerlemesini göstermek istiyorum.

Örneğin, bir hesaplama yöntemim varsa ve bunu Form sınıfımda 100000 değer için kullanmak istersem yazabilirim:

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
    }            

    private void Caluculate(int i)
    {
        double pow = Math.Pow(i, i);
    }

    private void button1_Click(object sender, EventArgs e)
    {
        progressBar1.Maximum = 100000;
        progressBar1.Step = 1;

        for(int j = 0; j < 100000; j++)
        {
            Caluculate(j);
            progressBar1.PerformStep();
        }
    }
}

Her hesaplamadan sonra adım atmalıyım. Ama ya 100000 hesaplamanın tamamını harici yöntemde yaparsam? Bu yöntemi ilerleme çubuğuna bağımlı yapmak istemiyorsam ne zaman "adım gerçekleştirmeliyim"? Örneğin yazabilirim

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
    }

    private void CaluculateAll(System.Windows.Forms.ProgressBar progressBar)
    {
        progressBar.Maximum = 100000;
        progressBar.Step = 1;

        for(int j = 0; j < 100000; j++)
        {
            double pow = Math.Pow(j, j); //Calculation
            progressBar.PerformStep();
        }
    }

    private void button1_Click(object sender, EventArgs e)
    {
        CaluculateAll(progressBar1);
    }
}

ama ben böyle yapmak istemiyorum.


4
Yönteme bir temsilci nesnesi iletin.
Hans Passant

Yanıtlar:


112

BackgroundWorker'a bir göz atmanızı öneririm . WinForm'unuzda bu kadar büyük bir döngünüz varsa, engellenecek ve uygulamanız askıda kalmış gibi görünecektir.

Bak BackgroundWorker.ReportProgress()UI iş parçacığı ilerleme geri rapor nasıl görmek.

Örneğin:

private void Calculate(int i)
{
    double pow = Math.Pow(i, i);
}

private void button1_Click(object sender, EventArgs e)
{
    progressBar1.Maximum = 100;
    progressBar1.Step = 1;
    progressBar1.Value = 0;
    backgroundWorker.RunWorkerAsync();
}

private void backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
{
    var backgroundWorker = sender as BackgroundWorker;
    for (int j = 0; j < 100000; j++)
    {
        Calculate(j);
        backgroundWorker.ReportProgress((j * 100) / 100000);
    }
}

private void backgroundWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
    progressBar1.Value = e.ProgressPercentage;
}

private void backgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
    // TODO: do something with final calculation.
}

5
Güzel örnek, ancak kodunuzda küçük bir hata var. BackgroundWorker.WorkerReportsProgress öğesini true olarak ayarlamanız gerekir. Düzenlememi kontrol et
Mana

1
@mana Varsayım, BackgroundWorkertasarımcı aracılığıyla eklendiği ve orada yapılandırıldığıdır. Ama evet, WorkerReportsProgressayarlanması için yapılandırılması gerekecek true.
Peter Ritchie

ah, benim hatam, tasarımcıda ayarlayabileceğinizi bilmiyordum
Mana

Yine de başka bir şeyi merak ediyorsanız, örneğiniz yalnızca 99 backgroundWorker.ReportProgress ((j * 100) / 100000); % 100 sayım nasıl elde edilir
Mana

1
@mana İlerlemenin% 100'ünü göstermek istiyorsanız, RunWorkerCompletedeylemciniz yapmazsa, olay işleyicide yapın DoWork..
Peter Ritchie

77

.NET 4.5'ten beri zaman uyumsuz kombinasyonunu kullanabilir ve UI iş parçacığına güncellemeler göndermek için İlerleme ile bekleyebilirsiniz :

private void Calculate(int i)
{
    double pow = Math.Pow(i, i);
}

public void DoWork(IProgress<int> progress)
{
    // This method is executed in the context of
    // another thread (different than the main UI thread),
    // so use only thread-safe code
    for (int j = 0; j < 100000; j++)
    {
        Calculate(j);

        // Use progress to notify UI thread that progress has
        // changed
        if (progress != null)
            progress.Report((j + 1) * 100 / 100000);
    }
}

private async void button1_Click(object sender, EventArgs e)
{
    progressBar1.Maximum = 100;
    progressBar1.Step = 1;

    var progress = new Progress<int>(v =>
    {
        // This lambda is executed in context of UI thread,
        // so it can safely update form controls
        progressBar1.Value = v;
    });

    // Run operation in another thread
    await Task.Run(() => DoWork(progress));

    // TODO: Do something after all calculations
}

Görevler şu anda ne BackgroundWorkerişe yaradığını uygulamanın tercih edilen yoludur .

Görevler ve Progressburada daha ayrıntılı olarak açıklanmıştır:


2
Bu seçilen cevap olmalı, IMO. Mükemmel cevap!
JohnOpincar

Normal bir eşzamansız işlev yerine Task.Run kullanması dışında neredeyse en güzel cevap
KansaiRobot

@KansaiRobot Aksine mi demek await DoWorkAsync(progress);istiyorsun? Bu, fazladan bir iş parçacığının çalışmasına neden olmayacağından, çok amaçlıdır. Yalnızca , örneğin bir G / Ç işlemini beklemek için DoWorkAsynckendi adını çağırırsa await, button1_Clickişlev devam eder. Ana UI iş parçacığı bu süre boyunca engellenir. DoWorkAsyncGerçekten eşzamansız değilse , ancak çok sayıda eşzamanlı ifade varsa, hiçbir şey kazanmazsınız.
Wolfzoon

System.Windows.Controls.ProgressBar bir "Adım" alanı içermiyor. Örnekten çıkarılmalıdır; özellikle zaten kullanılmadığı için.
Robert Tausig

2
@RobertTausig StepYalnızca WinForms'un ilerleme çubuğunda mevcut olduğu ve burada gerekli olmadığı doğru, ancak sorunun örnek kodunda (etiketli winformlar) mevcuttu, bu yüzden kalabilir.
quasoft

4

Hey, Dot Net inciler hakkında faydalı bir eğitim var: http://www.dotnetperls.com/progressbar

Peter ile hemfikir olarak, bir miktar iplik geçirmeniz gerekiyor, yoksa program sadece askıda kalacak ve amacı bir şekilde bozacaktır.

ProgressBar ve BackgroundWorker kullanan örnek: C #

using System.ComponentModel;
using System.Threading;
using System.Windows.Forms;

namespace WindowsFormsApplication1
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, System.EventArgs e)
        {
            // Start the BackgroundWorker.
            backgroundWorker1.RunWorkerAsync();
        }

        private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
        {
            for (int i = 1; i <= 100; i++)
            {
                // Wait 100 milliseconds.
                Thread.Sleep(100);
                // Report progress.
                backgroundWorker1.ReportProgress(i);
            }
        }

        private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            // Change the value of the ProgressBar to the BackgroundWorker progress.
            progressBar1.Value = e.ProgressPercentage;
            // Set the text.
            this.Text = e.ProgressPercentage.ToString();
        }
    }
} //closing here

1

Var Taskvar, kötülük kullanmak BackgroundWorker, Taskdaha basit. Örneğin:

ProgressDialog.cs:

   public partial class ProgressDialog : Form
    {
        public System.Windows.Forms.ProgressBar Progressbar { get { return this.progressBar1; } }

        public ProgressDialog()
        {
            InitializeComponent();
        }

        public void RunAsync(Action action)
        {
            Task.Run(action);
        }
    }

Bitti! Ardından ProgressDialog'u her yerde yeniden kullanabilirsiniz:

var progressDialog = new ProgressDialog();
progressDialog.Progressbar.Value = 0;
progressDialog.Progressbar.Maximum = 100;

progressDialog.RunAsync(() =>
{
    for (int i = 0; i < 100; i++)
    {
        Thread.Sleep(1000)
        this.progressDialog.Progressbar.BeginInvoke((MethodInvoker)(() => {
            this.progressDialog.Progressbar.Value += 1;
        }));
    }
});

progressDialog.ShowDialog();

Lütfen birden fazla soruya aynı cevapları göndermeyin . İyi bir cevap verin, ardından diğer soruları kopya olarak kapatmak için oylayın / işaretleyin. Soru yinelenen bir soru değilse , yanıtlarınızı soruya uyarlayın .
Martijn Pieters
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.