2013-04-22 10 views
5

मुझे नफ़रत है कि मेरा पहला प्रश्न कई बार उत्तर दिया गया है, लेकिन मुझे अभी भी पृष्ठभूमि कार्यकर्ता का उपयोग करके एक विधि को कॉल करने के तरीके के बारे में अपना सिर प्राप्त करने में कठिन समय है।BackgroundWorker से कॉल विधि

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

  • उपयोगकर्ता उपकरण पट्टी आइटम
  • उपयोगकर्ता एक फ़ाइल का चयन करता है एक संवाद बॉक्स के माध्यम से संसाधित करने के लिए
  • कार्रवाई

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

ऊपर से (। स्यूडोकोड उदाहरण उद्देश्यों के लिए इस्तेमाल बहुत संक्षिप्तता के लिए छोड़े गए):

private void ToolStripMenuItem_Click(object sender, EventArgs e) 
{ 
    string fileName = openSingleFile.FileName; 
    processFile(fileName); 
} 

static public void processFile(string fileName) 
{ 
// many vars/loops exist but not shown 

    foreach (data in bigData) 
    { 
     processItem(stringA, stringB); // <-- this method is where the expensive work is done 
     x++; 
    } 
} 

मैं BackgroundWorker का एक उदाहरण बना लिया है ...:

private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e) 
{ 
    // Things go here 
} 

... और मैंने सूची में बहुत सी चीजों की कोशिश की है, इसलिए मैं उपरोक्त प्रस्तुति के लिए शुरुआत में वापस गया हूं।

मैं BackgroundWorker समझने रहा हूँ, मैं निम्नलिखित कार्य करने होंगे:

  • बदलें processItem (stringA, STRING बिलियन) के साथ उपरोक्त कोड में कुछ की तरह:

    backgroundWorker1.RunWorkerAsync(processItem(stringA, stringB));

... और फिर कुछ प्रकार की DoWork कॉल करें? ... और फिर कुछ प्रकार के RunWorker पूर्ण कॉल करें?

यह सुनिश्चित नहीं है कि मेरा दिमाग क्यों ठंडा हो रहा है, लेकिन मैं इस पर खर्च किए गए समय पर शर्मिंदा हूं। किसी भी तरह की सहायता का स्वागत किया जाएगा। StackOverflow के बिना, मैं बहुत समय पहले डीओए होता।

एफवाईआई: मैंने अन्य एसओ पोस्ट, एमएसडीएन, और डॉटनेट पेर्ल्स उदाहरणों का संदर्भ दिया है। मुझे बस कुछ अवधारणा याद आ रही है, मुझे लगता है।

+0

अपनी सभी घटनाओं को बांधना न भूलें। bw.DoWork + = नया DoWorkEventHandler (bw_DoWork); bw.ProgressChanged + = नई प्रगतिChangedEventHandler (bw_ProgressChanged); bw.RunWorker पूर्ण + = नया RunWorkerCompletedEventHandler (bw_RunWorker पूर्ण); –

+0

अच्छा सवाल। मुझे बहुत कुछ –

उत्तर

3

बदलें processItem (stringA, STRING बिलियन) की तरह कुछ के साथ उपरोक्त कोड में ...

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

हल करने के लिए एकमात्र गैर-मामूली समस्या स्ट्रिंग को पार कर रही है जो प्रक्रिया() की आवश्यकता है। सौभाग्य से BackgroundWorker.RunWorkerAsync() में एक अधिभार है जो एक ही वस्तु लेता है। अपनी स्ट्रिंग पास करें। अपने DoWork इवेंट हैंडलर में अपना मान प्राप्त करें, एक स्ट्रिंग पर वापस e.Argument कास्टिंग करें। इस प्रकार:

private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e) { 
     string path = (string)e.Argument; 
     processFile(path); 
    } 

    private void processToolStripMenuItem_Click(object sender, EventArgs e) { 
     backgroundWorker1.RunWorkerAsync(openSingleFile.FileName); 
     processToolStripMenuItem.Enabled = false; 
    } 

    private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) { 
     processToolStripMenuItem.Enabled = true; 
    } 
+0

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

1

एक नया पृष्ठभूमि कार्यकर्ता शुरू करना एक महंगा ऑपरेशन है। आप एक लूप के प्रत्येक पुनरावृत्ति के लिए एक शुरू नहीं करना चाहते हैं। इसके बजाय, पूरे लूप को एक पृष्ठभूमि कार्यकर्ता के दायरे के अंदर रखें।

जब ToolStripMenuItem_Click आपके पृष्ठभूमि कार्यकर्ता को चलाता है, तो processFileDoWork ईवेंट हैंडलर में क्या किया जाता है।

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

यदि काम पूरा होने पर आपको UI को अपडेट करने की आवश्यकता है तो आप RunWorkerCompleted ईवेंट हैंडलर में ऐसा कर सकते हैं। यदि आप जो काम कर रहे हैं, वह कुछ परिणाम उत्पन्न करता है जिसका उपयोग UI को अद्यतन करने के लिए किया जाता है, तो पृष्ठभूमि कार्यकर्ता की Result संपत्ति का उपयोग पूरे हैंडलर को DoWork विधि से पास करने के लिए करें।

+0

धन्यवाद, आपके द्वारा किए गए अंक ध्यान दिए गए हैं और सामान्य रूप से एक नए धागे और इसके प्रभावों को बढ़ाने की मेरी समझ में योगदान करने में मदद मिली है। मैं आपकी इनपुट प्रदान करने के लिए समय निकालने की सराहना करता हूं, हालांकि मैंने एक और जवाब चुना है कि इस सवाल का पूरी तरह उत्तर दिया गया है (आपने मुझे फिर से योग्यता से अधिक क्रेडिट दिया है: बिना किसी जानकारी के समाधान को कार्यान्वित करने में सक्षम होना। दूसरे शब्दों में, यह मैं हूं , आप नहीं :) – LovinItAll

1
BackgroundWorker bgw; 

लोड घटना या निर्माता में:

bgw = new BackgroundWorker(); 
bgw.WorkerReportsProgress = true; 
//bgw.WorkerSupportsCancellation = true; 

bgw.DoWork += bgw_DoWork; 
bgw.ProgressChanged += bgw_ProgressChanged; 
bgw.RunWorkerCompleted += bgw_RunWorkerCompleted; 

/

private void ToolStripMenuItem_Click(object sender, EventArgs e) 
    { 
     string fileName = openSingleFile.FileName; 

     bgw.RunWorkerAsync(fileName); 
    } 

    private void bgw_DoWork(object sender, DoWorkEventArgs e) 
    { 
     string fileName = (string)e.Argument; 

     processFile(fileName); 
    } 

    private void bgw_ProgressChanged(object sender, ProgressChangedEventArgs e) 
    { 
     int Progress = e.ProgressPercentage; 

     //Update progressbar here 
    } 

    private void bgw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) 
    { 
     //Job completed 
    } 
+1

मैंने दिए गए स्पष्टीकरण के कारण एक और जवाब चुना है, लेकिन कृपया ध्यान दें कि आपका कोड सीधे मेरे समाधान को काम करता है, विशेष रूप से लोड ईवेंट में पृष्ठभूमिवर्कर जानकारी को शामिल करने के निर्देश। यह एक जवाब चुनना बहुत मुश्किल था - मैं भी उस पर सोया। अपने कोड को डब्ल्यू/आउट करें, मैंने अपने समाधान पर अधिक समय बिताया होगा, लेकिन मैंने जो जवाब चुना है, उसमें स्पष्टीकरण को बाहर निकालना होगा, मैं बस अपनी समझ को आगे बढ़ाने के समाधान को कॉपी और पेस्ट कर रहा हूं। कृपया ध्यान रखें कि आपका उत्तर चुनना मुश्किल नहीं था .... धन्यवाद। – LovinItAll

+0

यह सब अच्छा है, खुशी है कि मैं – kschieck

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