2010-07-21 15 views
13

मुझे एक सी # विंडोज़ फॉर्म ऐप मिला है जिसे मैंने एक साथ फेंक दिया है। यह काफी सरल है: \सी # पृष्ठभूमि कार्यकर्ता प्रक्रिया का उपयोग करके टेक्स्टबॉक्स मान अपडेट करें और संलग्न करें

आदानों:

  • पाठ स्ट्रिंग
  • स्रोत फ़ोल्डर पथ
  • गंतव्य फ़ोल्डर पथ
  • पूर्णांक

एप्लिकेशन खोजों का टेक्स्ट फ़ाइलों के माध्यम से गिनती दर्ज टेक्स्ट स्ट्रिंग के लिए स्रोत फ़ोल्डर; यदि यह स्ट्रिंग पाता है तो यह उस फ़ाइल और एक छवि फ़ाइल को उसी फ़ोल्डर के साथ गंतव्य फ़ोल्डर में कॉपी करता है। हालांकि यह पूर्णांक इनपुट के आधार पर कई बार ऐसा करता है।

तो मैं एक बटन है, और बटन क्लिक करें घटना में मैं

ProcessImages(tbDID.Text, tbSource.Text, tbDest.Text, comboBoxNumberImages.SelectedItem.ToString()); 

जो फोन:

private void ProcessImages(string DID, string SourceFolder, string DestFolder, string strNumImages) 
     {   
      int ImageCounter = 0; 
      int MaxImages = Convert.ToInt32(strNumImages); 

      DirectoryInfo di = new DirectoryInfo(SourceFolder); 

      foreach (FileInfo fi in di.GetFiles("*.txt")) 
      { 
       if (fi.OpenText().ReadToEnd().Contains(DID)) 
       { 
        //found one! 
        FileInfo fi2 = new FileInfo(fi.FullName.Replace(".txt", ".tif")); 
        if (fi2.Exists) 
        { 
         try 
         { 
          tbOutput.Text += "Copying " + fi2.FullName + " to " + tbDest.Text + "\r\n"; 
          fi2.CopyTo(tbDest.Text + @"\" + fi2.Name, true); 
          tbOutput.Text += "Copying " + fi.FullName + " to " + tbDest.Text + "\r\n"; 
          fi.CopyTo(tbDest.Text + @"\" + fi.Name, true); 

          ImageCounter++; 
         } 
         catch (Exception ex) 
         { 
          MessageBox.Show(ex.Message); 
         } 
        } 
       } 

       if (ImageCounter >= MaxImages) 
        break; 

      } 

     } 

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

मैंने उदाहरणों को देखा है लेकिन वास्तव में उनका पालन नहीं कर रहा हूं। मेरे पास प्रतिशत पूर्ण मूल्य नहीं है, मैं बस अपडेट करना चाहता हूं। टेक्स्ट प्रत्येक पुनरावृत्ति को बदलता है और इसे प्रदर्शित करता है। मुझे यह भी नहीं लगता कि मुझे वास्तविक प्रतिलिपि कार्रवाई को अलग-अलग धागे में रखना होगा, ऐसा लगता है कि इसे मुख्य UI थ्रेड से अलग से चलाने की आवश्यकता है। हो सकता है कि मैं इसे पूरी तरह से जटिल कर रहा हूं ... क्या कोई मुझे सही दिशा में धक्का दे सकता है? धन्यवाद!

उत्तर

7

यदि आप पृष्ठभूमि कार्यकर्ता का उपयोग करते हैं तो आप किसी भी पूर्णांक को वापस करने के लिए ReportProgress विधि का उपयोग कर सकते हैं, जैसे संसाधित रिकॉर्ड्स की संख्या। यह प्रतिशत नहीं होना चाहिए। फिर, प्रोग्रेस चेंज हैंडलर में आप अपना टेक्स्टबॉक्स अपडेट कर सकते हैं। जैसे

int count = e.ProgressPercentage; 
textBox1.Text = string.Format("{0} images processed.", count); 

आप एक पृष्ठभूमि कार्यकर्ता उपयोग करने के लिए आप Application.DoEvents() कॉल कर सकते हैं अपने पाश अंदर नहीं करना चाहते हैं। इससे यूआई को खुद को ताज़ा करने और उपयोगकर्ता कार्यों का जवाब देने का मौका मिलेगा। लेकिन सावधान रहें - यह आपके प्रोग्राम को बहुत धीमा कर देगा ताकि आप इसे केवल 100 वें पुनरावृत्ति पर कॉल कर सकें।

2

यूआई अपडेट नहीं होता है क्योंकि आप किसी भी विंडो संदेशों को आपके लंबे समय तक चलने वाली फ़ाइल प्रोसेसिंग लूप में संसाधित करने की अनुमति नहीं दे रहे हैं। WinForms ऐप्स WM_PAINT संदेशों के जवाब में पुन: क्रॉल करते हैं जो मुख्य थ्रेड में संदेश कतार में संसाधित होते हैं।

सबसे आसान समाधान यूआई अपडेट को मजबूर करना है: अपने लूप के अंदर टेक्स्टबॉक्स को संशोधित करने के बाद अपडेट() को कॉल करने का प्रयास करें।

आपका ऐप अभी भी यूआई जमे हुए (माउस क्लिक के लिए उत्तरदायी नहीं होगा) लेकिन इसे कम से कम स्क्रीन पर खींचे गए प्रगति संदेश प्राप्त करना चाहिए। यदि डिस्प्ले अपडेट करना आपको वास्तव में जरूरी है, तो यहां रुकें।

समाधान का अगला स्तर आपके फ़ाइल प्रसंस्करण पाश में लंबित विंडो संदेशों को संसाधित करने की अनुमति देगा। अपने लूप में एप्लिकेशन (DoEvents) को कॉल करें (फॉर्म के बजाय। अद्यतन करें)। यह फ़ॉर्म को आपके टेक्स्ट आउटपुट अपडेट के साथ खुद को फिर से निकालने की अनुमति देगा और आपके यूआई फ्रीज को खत्म कर देगा - ऐप माउस और कीबोर्ड गतिविधि का जवाब दे सकता है।

यहां सावधान रहें, हालांकि - उपयोगकर्ता वर्तमान गतिविधि शुरू होने पर वर्तमान गतिविधि शुरू करने वाले बटन पर क्लिक कर सकता है - पुनर्वितरण। आपको कम से कम मेनू या बटन को अक्षम करना चाहिए जो पुनर्वित्त को रोकने के लिए आपकी लंबी-चलती फ़ाइल प्रसंस्करण को बंद कर देता है।

फ़ाइल प्रसंस्करण के लिए पृष्ठभूमि थ्रेड का उपयोग करने का एक तीसरा स्तर समाधान होगा। यह उन नए मुद्दों की एक पूरी मेजबानी पेश करता है जिनके बारे में आपको अवगत होना चाहिए, और कई मामलों में धागे अधिक हो गए हैं।फाइल प्रसंस्करण हो रहा है, जबकि फ़ाइल प्रसंस्करण हो रहा है, जबकि फ़ाइल प्रसंस्करण हो रहा है, जब आप उपयोगकर्ता को अपने ऐप के साथ कुछ और करने की अनुमति नहीं दे रहे हैं।

+0

ओपी सही रास्ते, BackgroundWorker, जो दोनों पृष्ठभूमि धागा बनाता है उपयोग करने के लिए है, जिस पर पहले से ही है (अच्छी तरह से, यह एक का उपयोग करता है पूल थ्रेड), और आपके पिछले अनुच्छेद में बताए गए कुछ मुद्दों से संबंधित है। –

+0

ओपी यह इंगित नहीं करता है कि फ़ाइल प्रोसेसिंग होने पर यूआई में यूजर में कुछ और करने के लिए है, इसलिए पृष्ठभूमि थ्रेड आईएमओ ओवरकिल हो सकता है। – dthorpe

13

आप पृष्ठभूमि कार्यकर्ता के साथ सही रास्ते पर हैं। यहां एक उदाहरण दिया गया है जो मैंने आपको यह दिखाने के लिए एक साथ रखा है कि यह कैसे करें। फॉर्म 1 के साथ एक नया विंडोज ऐप बनाएं। इसमें 4 नियंत्रण जोड़ें: लेबल 1, पृष्ठभूमि वर्कर 1, बटन 1, और बटन 2। फिर इस कोड के पीछे का प्रयोग करें। फिर आप जो भी चाहें मुख्य थ्रेड पर रिपोर्ट करने के लिए ReportProgress UserState का उपयोग कर सकते हैं। इस उदाहरण में, मैं एक स्ट्रिंग पास कर रहा हूँ। प्रोग्रेस चेंज इवेंट हैंडलर यूआई थ्रेड पर है, और टेक्स्टबॉक्स अपडेट करता है।

public partial class Form1 : Form 
{ 
    int backgroundInt; 
    public Form1() 
    { 
     InitializeComponent(); 
     backgroundWorker1.WorkerReportsProgress = true; 
    } 

    private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e) 
    { 
     label1.Text = e.UserState as string; 
    } 

    private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e) 
    { 
     backgroundInt = 1; 
     while (backgroundWorker1.CancellationPending == false) 
     { 
      System.Threading.Thread.Sleep(500); 
      backgroundWorker1.ReportProgress(0, 
       String.Format("I found file # {0}!", backgroundInt)); 
      backgroundInt++; 
     } 
    } 


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

    private void button2_Click(object sender, EventArgs e) 
    { 
     backgroundWorker1.CancelAsync(); 
    } 
} 
+4

और ओपी के मूल 'मेरे पास प्रतिशत नहीं है' शिकायत के मामले में यहां महत्वपूर्ण बिंदु यह है कि रिपोर्ट प्रगति न केवल प्रतिशत ले सकती है, बल्कि * एक सामान्य उद्देश्य वस्तु - जो (इस उदाहरण में) हो सकती है एक स्ट्रिंग। स्ट्रिंग के रूप में e.UserState के लिए –

+0

+1। वह मेरे लिए स्पष्ट से बहुत दूर था। – Jahmic

1

बस (2) आग कॉल बंद एक प्रतिनिधि का उपयोग कर, और (3) जब आप अपने ProcessImages विधि से पाठ बॉक्स अपडेट नहीं करना चाहते, चेक आपके ProcessImages विधि कॉल रैप करने के लिए एक (1) एक प्रतिनिधि बनाने के लिए, पार thead ऑपरेशन के लिए और आप मुख्य थ्रेड से अद्यतन करना सुनिश्चित करें:

delegate void ProcessImagesDelegate(string did, string sourceFolder, string destFolder, string strNumImages); 

private void ProcessImages(string DID, string SourceFolder, string DestFolder, string strNumImages) 
{ 
    // do work 

    // update textbox in form 
    if (this.textBox1.InvokeRequired) 
    { 
     this.textBox1.Invoke(new MethodInvoker(delegate() { this.textBox1.Text = "delegate update"; })); 
    } 
    else 
    { 
     this.textBox1.Text = "regular update"; 
    } 

    // do some more work 
} 

public void MyMethod() 
{ 
    new ProcessImagesDelegate(ProcessImages).BeginInvoke(tbDID.Text, tbSource.Text, tbDest.Text, comboBoxNumberImages.SelectedItem.ToString(), null, null); 
} 
+0

पृष्ठभूमिवर्कर का उपयोग करने से यह बेहतर क्यों है? –

+0

चूंकि वे दोनों थ्रेड पूल का उपयोग करते हैं और कोई भी मुझे दूसरे पर बेहतर प्रदर्शन नहीं देता है, इसलिए मैं प्रतिनिधियों को बेहतर पसंद करता हूं क्योंकि वे आम तौर पर मुझे क्लीनर/सरल कोड (इम्हो) देते हैं, साथ ही यह यह पूरा करने का एक और तरीका है कि वह क्या कर रहा है चाहता हे – Jason

संबंधित मुद्दे