2009-09-24 5 views
15

मुझे इस तरह की समस्या है:सी # विनफॉर्म प्रोग्रेसबार और पृष्ठभूमिवर्कर

मेरे पास मेनफॉर्म नामक एक फॉर्म है। मेरे पास इस फॉर्म पर होने वाला एक लंबा ऑपरेशन है।

हालांकि यह लंबा ऑपरेशन चल रहा है, मुझे मेनफॉर्म के शीर्ष पर नाम प्रगतिफॉर्म से दूसरा दिखाना होगा।

प्रोग्रेसफॉर्म में प्रगति पट्टी शामिल है। लंबे ऑपरेशन के दौरान अपडेट होने की जरूरत है।

लंबे ऑपरेशन पूरा होने के बाद, प्रोग्रेसफॉर्म स्वचालित रूप से बंद होना चाहिए।

मैं निम्नलिखित की तरह कुछ कोड लिखा है:

using System; 
using System.Collections.Generic; 
using System.Text; 
using System.Windows.Forms; 
using System.Threading; 

namespace ClassLibrary 
{ 
    public class MyClass 
    { 
     public static string LongOperation() 
     { 
      Thread.Sleep(new TimeSpan(0,0,30)); 

      return "HelloWorld"; 
     } 
    } 
} 

using System; 
using System.Collections.Generic; 
using System.ComponentModel; 
using System.Data; 
using System.Drawing; 
using System.Text; 
using System.Windows.Forms; 

namespace BackgroungWorker__HelloWorld 
{ 
    public partial class ProgressForm : Form 
    { 
     public ProgressForm() 
     { 
      InitializeComponent(); 
     } 

     public ProgressBar ProgressBar 
     { 
      get { return this.progressBar1; } 
      set { this.progressBar1 = value; } 
     } 
    } 
} 

using System; 
using System.Collections.Generic; 
using System.ComponentModel; 
using System.Data; 
using System.Drawing; 
using System.Text; 
using System.Windows.Forms; 

using ClassLibrary; 

namespace BackgroungWorker__HelloWorld 
{ 
    public partial class MainForm : Form 
    { 
     ProgressForm f = new ProgressForm(); 

     public MainForm() 
     { 
      InitializeComponent(); 
     } 

     int count = 0; 
     private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e) 
     { 
      if (f != null) 
      { 
       f.ProgressBar.Value = e.ProgressPercentage; 
      } 

      ++count; 
     } 

     private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) 
     { 
      if (e.Cancelled) 
      { 
       MessageBox.Show("The task has been cancelled"); 
      } 
      else if (e.Error != null) 
      {     
       MessageBox.Show("Error. Details: " + (e.Error as Exception).ToString()); 
      } 
      else 
      { 
       MessageBox.Show("The task has been completed. Results: " + e.Result.ToString()); 
      } 
     } 


     private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e) 
     { 
      if (f == null) 
      { 
       f = new ProgressForm(); 
      } 

      f.ShowDialog(); 

      //backgroundWorker1.ReportProgress(100); 

      MyClass.LongOperation(); 

      f.Close(); 
     } 

     private void btnStart_Click(object sender, EventArgs e) 
     { 
      backgroundWorker1.RunWorkerAsync(); 
     } 

     private void btnCancel_Click(object sender, EventArgs e) 
     { 
      backgroundWorker1.CancelAsync(); 

      this.Close(); 
     } 
    } 
} 

मैं Progressbar अद्यतन करने के लिए जिस तरह से नहीं मिल रहा हूँ।

मुझे backgroundWorker1.ReportProgress() कहां रखना चाहिए और मुझे इसे कैसे कॉल करना चाहिए?

मुझे MyClass में कोई भी बदलाव नहीं करना चाहिए। Coz, मुझे नहीं पता कि क्या होगा या मेरे आवेदन की इस परत में ऑपरेशन को पूरा करने में कितना समय लगेगा।

क्या कोई मेरी मदद कर सकता है?

उत्तर

12

एक समस्या यह है कि आप 30 सेकंड के लिए सो रहे हैं। आम तौर पर आप अपने लंबे समय तक चलने वाले कार्य के भीतर विभिन्न बिंदुओं पर ReportProgress पर कॉल करेंगे। तो इसे प्रदर्शित करने के लिए, हो सकता है कि आप अपना कोड 1 सेकंड के लिए सोने के लिए बदलना चाहें, लेकिन 30 बार - ReportProgress पर कॉल करते समय प्रत्येक बार नींद खत्म हो जाती है।

एक और समस्या यह है कि आप अपने ProgressFormको पृष्ठभूमि थ्रेड से दिखा रहे हैं। आपको इसे UI धागे में शुरू करना चाहिए, लेकिन पृष्ठभूमि कार्यकर्ता के ProgressChanged ईवेंट को हुक करना चाहिए। फिर जब पृष्ठभूमि कार्यकर्ता प्रगति की रिपोर्ट करता है, तो प्रगति फॉर्म अपडेट किया जाएगा।

+0

मुझे MyClass में कोई भी बदलाव नहीं करना चाहिए। Coz, मुझे नहीं पता कि मेरे ऐप की इस परत में क्या होगा। – anonymous

+6

फिर आप प्रगति की सटीक रिपोर्ट नहीं कर सकते हैं। मेरा मतलब है कि आप प्रत्येक प्रगति पट्टी को हर सेकेंड में बढ़ाने के लिए 'प्रोग्रेसफॉर्म' में टाइमर जोड़ सकते हैं, लेकिन यह केवल भ्रम प्रदान करेगा। यदि आपके पास * वास्तविक * प्रगति का पता लगाने का कोई तरीका नहीं है, तो प्रगति पट्टी कितनी उपयोगी है? –

2

रिपोर्ट प्रोग्रेस वह तरीका है जिसे आपको अपनी 'कामकाजी' विधि में कॉल करना होगा। यह विधि 'प्रोग्रेस चेंज' ईवेंट बढ़ाएगी।

अपने फॉर्म में, आप प्रोग्रेस चेंज किए गए ईवेंट में इवेंटहालर संलग्न कर सकते हैं। उस घटनास्थल के अंदर, आप प्रगति पट्टी की स्थिति बदल सकते हैं। आप RunWorker पूर्ण ईवेंट में इवेंट हैंडलर भी संलग्न कर सकते हैं, और उस ईवेंटशेलर के अंदर, आप उस प्रपत्र को बंद कर सकते हैं जिसमें प्रोग्रेसबार है।

+0

यह एक सामान्य समाधान है जो मुझे लगता है। Plz फिर से समस्या पढ़ें। – anonymous

2

ऐसा लगता है आप

backgroundWorker1.WorkerReportsProgress = true; 

निर्धारित करने की आवश्यकता है, तो आप पृष्ठभूमि कार्यकर्ता ProgressChanged घटना को बढ़ाने के लिए चाहते हैं और

backgroundWorker1.WorkerSupportsCancellation = true; 

अगर आप कार्यकर्ता धागा रद्द करने के लिए सक्षम होने के लिए चाहते हैं।

जैसा कि अन्य ने कहा है, अपने यूआई थ्रेड में f.ShowDialog() चलाएं और प्रोग्रेसविंडो को अपडेट करने के लिए प्रोग्रेस चेंज का उपयोग करें।

प्रोग्रेसफॉर्म को स्वयं बंद करने के लिए, पृष्ठभूमि में वर्कर 1_RunWorker पूर्ण, कॉल एफ।बंद करे(); इसका मतलब है कि लंबा ऑपरेशन पूरा हो गया है और हम विंडो बंद कर सकते हैं।

+0

UI थ्रेड से प्रोग्रेसविंडो को कॉल करने का क्या फायदा है? – anonymous

0

कक्षा में पूरे मुख्य रूप को पारित करने की आवश्यकता नहीं है, लेकिन बस आपके पृष्ठभूमिवर्कर का उदाहरण है! तुम इतनी तरह पृष्ठभूमि कार्यकर्ता के रूप में इस कास्ट करने के लिए की जरूरत है:

private void bgWorker_DoWork(object sender DoWorkEventArgs e) 
{ 
    // Get the BackgroundWorker that raised this event 
    BackgroundWorker worker = sender as BackgroundWorker; 

    // And now you just send worker to whatever class you need like so: 
    bgArgs args = e.Argument as bgArgs; 
    MyClass objMyClass = new MyClass(); 

    MyClass.MyMethod(strValue, args.Option, worker); 

    // Do something based on return value. 
} 

और फिर में अपने MyClass.MyMethod() आप प्रगति गणना करना होगा और केवल प्रगति बार या whatnot आपका मुख्य यूआई फार्म पर अद्यतन करने के लिए worker.ReportProgress(int percentage) ईवेंट उत्पन्न!

यह पूरी तरह से काम करना चाहिए!

अधिक जानकारी के लिए इस एमएसडीएन आलेख को देखें, उनके फिबोनासी उदाहरण देखें, CalculateFibonacci के बाद से वे एक कस्टम क्लास है जो मुख्य फॉर्म के यूआई को अपडेट भेजता है। अधिक जानकारी के लिए

MSDN BackgroundWorker Class देखें।