2012-12-31 21 views
5

मैं WinForms C# अनुप्रयोग में एक अलग थ्रेड रखने की कोशिश कर रहा हूं, एक पृष्ठभूमि कार्यकर्ता शुरू करता है जो प्रोग्रेसबार (मार्की) को नियंत्रित करता है। मुद्दा यह है कि जब मैं बार को दृश्यमान करने के लिए सेट करने की कोशिश करता हूं तो यह कुछ भी नहीं करता है, और मैंने कई प्रकार के आमंत्रण की कोशिश की है लेकिन वे मदद नहीं कर रहे हैं।यूआई तत्वों को किसी अन्य धागे के भीतर से जोड़ना

निम्न विधि progressBarCycle को एक अलग थ्रेड से बुलाया जाता है।

BackgroundWorker backgroundWorker = new BackgroundWorker(); 

    public void progressBarCycle(int duration) 
    { 
     backgroundWorker.DoWork += new DoWorkEventHandler(backgroundWorker_DoWork); 
     backgroundWorker.ProgressChanged += new ProgressChangedEventHandler(backgroundWorker_ProgressChanged); 
     backgroundWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(backgroundWorker_RunWorkerCompleted); 
     backgroundWorker.WorkerReportsProgress = true; 
     backgroundWorker.WorkerSupportsCancellation = true; 
     backgroundWorker.RunWorkerAsync(duration); 
    } 

    private void backgroundWorker_DoWork(object sender, DoWorkEventArgs e) 
    { 
     BackgroundWorker worker = sender as BackgroundWorker; 

     worker.ReportProgress(0); 

     DateTime end = DateTime.Now.AddMilliseconds((int)e.Argument); 
     while (DateTime.Now <= end) 
     { 
      System.Threading.Thread.Sleep(1000); 
     } 
    } 

    private void backgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) 
    { 
     if (!this.IsHandleCreated) 
      this.CreateHandle(); 
     statusStrip1.Invoke((MethodInvoker)delegate 
     { 
      progressBar1.Visible = false; 
     }); 
     // if (!this.IsHandleCreated) 
     // { 
     //  this.CreateHandle(); 
     //  if (InvokeRequired) this.Invoke((MethodInvoker)(() => progressBar1.Visible = false)); 
     //  else progressBar1.Visible = false; 
     // } 
     // else 
     //  if (InvokeRequired) this.Invoke((MethodInvoker)(() => progressBar1.Visible = false)); 
     //  else progressBar1.Visible = false; 
    } 

    private void backgroundWorker_ProgressChanged(object sender, ProgressChangedEventArgs e) 
    { 
     if (!this.IsHandleCreated) 
      this.CreateHandle(); 
     statusStrip1.Invoke((MethodInvoker)delegate 
     { 
      progressBar1.Visible = true; 
     }); 
     // if (!this.IsHandleCreated) 
     // { 
     //  this.CreateHandle(); 
     //  if (InvokeRequired) this.Invoke((MethodInvoker)(() => progressBar1.Visible = true)); 
     //  else progressBar1.Visible = true; 
     // } 
     // else 
     //  if (InvokeRequired) this.Invoke((MethodInvoker)(() => progressBar1.Visible = true)); 
     //  else progressBar1.Visible = true; 
    } 

क्या मुझे यहां कुछ स्पष्ट याद आ रही है? टिप्पणी अनुभाग अन्य चीजें हैं जिनकी मैंने कोशिश की है।

उत्तर

6

ProgressChangedपहले से ही यूआई थ्रेड (सिंक-संदर्भ के माध्यम से) पर उठाया गया है; आपके ProgressChanged को Invoke करने की आवश्यकता नहीं है - यह सीधे यूआई में हेरफेर कर सकता है (इसके विपरीत, DoWork बिल्कुल ऐसा नहीं कर सकता है)। शायद वास्तविक समस्या यह है कि आप लूप के अंदर नहीं करते हैं - इसलिए यह केवल शुरुआत में ही होता है। यूआई धागे से

using System; 
using System.ComponentModel; 
using System.Threading; 
using System.Windows.Forms; 
static class Program 
{ 
    [STAThread] 
    static void Main() 
    { 
     Application.EnableVisualStyles(); 
     using (var worker = new BackgroundWorker { 
      WorkerReportsProgress = true }) 
     using (var progBar = new ProgressBar { 
      Visible = false, Step = 1, Maximum = 100, 
      Dock = DockStyle.Bottom }) 
     using (var btn = new Button { Dock = DockStyle.Top, Text = "Start" }) 
     using (var form = new Form { Controls = { btn, progBar } }) 
     { 
      worker.ProgressChanged += (s,a) => { 
       progBar.Visible = true; 
       progBar.Value = a.ProgressPercentage; 
      }; 
      worker.RunWorkerCompleted += delegate 
      { 
       progBar.Visible = false; 
      }; 
      worker.DoWork += delegate 
      { 
       for (int i = 0; i < 100; i++) 
       { 
        worker.ReportProgress(i); 
        Thread.Sleep(100); 
       } 
      }; 
      btn.Click += delegate 
      { 
       worker.RunWorkerAsync(); 
      }; 
      Application.Run(form); 
     } 
    } 
} 
+0

मैंने प्रोग्रेस चेंज और रनवर्कर में रखा है यह देखने के लिए पूरी तरह से पूर्ण किया गया है कि यह मेरी समस्या को ठीक करेगा या नहीं। जब मेरे पास उस कोड को DoWork में शामिल किया गया था, तो यह वही काम करेगा।दृश्यमान राज्य कभी भी बिना किसी आमंत्रण के या बिना बदल देगा। - ओह और शायद यह उल्लेखनीय है कि यह एक मार्की है इसलिए मैं प्रगति रिपोर्ट का उपयोग करने का इरादा नहीं रखता हूं। – UncleDave

+0

@UncleDave तो ऐसा लगता है कि प्रगति-बार एक और नियंत्रण (पैनल शायद) के अंदर है जो दिखाई नहीं दे रहा है। –

+0

प्रगति पट्टी इस कोड को चलाने वाले फॉर्म पर है, जो कि एप्लिकेशन का प्रारंभिक रूप भी है। – UncleDave

2
  1. भागो progressBarCycle:

    यहाँ एक पूर्ण उदाहरण है। RunWorkerAsync आपके लिए नया धागा बना देगा।

  2. backgroundWorker_ProgressChanged में बस progressBar1.Visible = true; पर कॉल करें। Invoke की कोई आवश्यकता नहीं है।
  3. बेहतर भी progressBar1.Refresh(); जोड़ें।
2

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

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

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

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