WinForms प्रगति पट्टी का उपयोग कैसे करें?


101

मैं गणनाओं की प्रगति दिखाना चाहता हूं, जो बाहरी पुस्तकालय में प्रदर्शन कर रहे हैं।

उदाहरण के लिए यदि मेरे पास कुछ गणना विधि है, और मैं इसे अपने प्रपत्र वर्ग में 100000 मूल्यों के लिए उपयोग करना चाहता हूं जो मैं लिख सकता हूं:

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();
        }
    }
}

मुझे प्रत्येक गणना के बाद कदम उठाना चाहिए। लेकिन क्या होगा अगर मैं बाहरी पद्धति में सभी 100000 गणना करता हूं। यदि मुझे इस पद्धति को प्रगति पट्टी पर निर्भर नहीं बनाना है तो मुझे "चरण प्रदर्शन" कब करना चाहिए? मैं, उदाहरण के लिए, लिख सकता हूं

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);
    }
}

लेकिन मैं ऐसा नहीं करना चाहता।


4
विधि के लिए एक प्रतिनिधि ऑब्जेक्ट पास करें।
हंस पसंत

जवाबों:


112

मेरा सुझाव है कि आप BackgroundWorker पर एक नज़र है । यदि आपके पास एक लूप है जो आपके WinForm में बड़ा है तो यह ब्लॉक हो जाएगा और आपका ऐप ऐसा लगेगा जैसे उसने फांसी लगा ली है।

यह देखने के BackgroundWorker.ReportProgress()लिए कि UI थ्रेड में प्रगति की रिपोर्ट कैसे करें।

उदाहरण के लिए:

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
अच्छा उदाहरण है, लेकिन आपके कोड में एक छोटी सी त्रुटि है। आपको बैकग्राउंडवॉकर सेट करना होगा। VorkerReportsProgress को सच करना। मेरा संपादन जांचें
मन

1
@mana धारणा यह है कि BackgroundWorkerडिजाइनर के माध्यम से जोड़ा जाता है और वहां कॉन्फ़िगर किया जाता है। लेकिन हां, इसे WorkerReportsProgressसेट करने के लिए कॉन्फ़िगर करने की आवश्यकता होगी true
पीटर रिची

आह, मेरा बुरा, यह नहीं जानता था कि आप इसे डिजाइनर में सेट कर सकते हैं
मैना

हालांकि कुछ और आश्चर्य की बात है, आपका उदाहरण केवल 99 पृष्ठभूमि के लोगों के लिए मायने रखता है। ReportProgress ((j * 100) / 100000); 100% गिनती कैसे प्राप्त करें
मान

1
@mana यदि आप प्रगति में 100% दिखाना चाहते हैं, तो RunWorkerCompletedइवेंट हैंडलर में करें, यदि आपका DoWorkहैंडलर ऐसा नहीं करता है ..
पीटर रिची

77

.NET 4.5 के बाद से आप async के संयोजन का उपयोग कर सकते हैं और UI थ्रेड में अपडेट भेजने के लिए प्रगति के साथ प्रतीक्षा कर सकते हैं :

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
}

वर्तमान में कार्य जो BackgroundWorkerकरता है उसे लागू करने का पसंदीदा तरीका है।

कार्य यहां और Progressअधिक विस्तार से बताए गए हैं:


2
यह चयनित उत्तर, IMO होना चाहिए। बहुत बढ़िया जवाब!
जॉनऑपिनकर

लगभग लगभग सबसे अच्छा जवाब है, सिवाय इसके कि यह एक सामान्य async समारोह के बजाय Task.Run उपयोग कर रहा है
KansaiRobot

@ KansaiRobot आप के रूप में विरोध का मतलब है await DoWorkAsync(progress);? यह उद्देश्य पर बहुत अधिक है, क्योंकि इससे एक अतिरिक्त धागा नहीं चल पाएगा। केवल अगर DoWorkAsyncयह स्वयं के awaitलिए कॉल करेगा जैसे कि I / O ऑपरेशन पर प्रतीक्षा कर रहा है, तो button1_Clickफ़ंक्शन जारी रहेगा। इस अवधि के लिए मुख्य UI थ्रेड अवरुद्ध है। यदि DoWorkAsyncवास्तव में एसिंक्रोनस नहीं है, लेकिन बहुत सारे सिंक्रोनस स्टेटमेंट्स हैं, तो आप कुछ हासिल नहीं करते हैं।
वोल्फज़ून

System.Windows.Controls.ProgressBar में "चरण" फ़ील्ड शामिल नहीं है। इसे उदाहरण से हटा दिया जाना चाहिए; विशेष रूप से यह वैसे भी प्रयोग नहीं किया जाता है।
रॉबर्ट तौसिग

2
@RobertTausig यह सच है जो Stepकेवल WinForms के प्रगति बार में उपलब्ध है और यहां इसकी आवश्यकता नहीं है, लेकिन यह प्रश्न के उदाहरण कोड (टैग किए गए winforms) में मौजूद था, इसलिए यह रह सकता है।
क्वासॉफ्ट

4

अरे, डॉट नेट मोती पर एक उपयोगी ट्यूटोरियल है: http://www.dotnetperls.com/progressbar

पीटर के साथ समझौते में, आपको थ्रेडिंग की कुछ मात्रा का उपयोग करने की आवश्यकता है या कार्यक्रम बस लटकाएगा, कुछ हद तक उद्देश्य को हरा देगा।

ProgressBar और BackgroundWorker का उपयोग करने वाला उदाहरण: 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

वहाँ Taskमौजूद है, यह प्रयोग करने में असावधानी है BackgroundWorker, Taskअधिक सरल है। उदाहरण के लिए:

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);
        }
    }

किया हुआ! तब आप कहीं भी ProgressDialog का पुन: उपयोग कर सकते हैं:

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();

कृपया कई प्रश्नों के समान उत्तर न दें । एक अच्छा उत्तर पोस्ट करें, फिर डुप्लिकेट के रूप में अन्य प्रश्नों को बंद करने के लिए वोट / ध्वज दें। यदि प्रश्न डुप्लिकेट नहीं है, तो प्रश्न के अपने उत्तरों को दर्जी करें
मार्टिन पीटर्स
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.