2009-09-14 5 views
10

मैं एक समारोहथ्रेड Control.Invoke

public void ShowAllFly() 
{ 
     cbFly.Items.Clear(); 
     cbFly.Items.Add("Uçuş Seçiniz..."); 

     dsFlyTableAdapters.tblFlyTableAdapter _t=new KTHY.dsFlyTableAdapters.tblFlyTableAdapter(); 
     dsFly _mds = new dsFly(); 
     _mds.EnforceConstraints = false; 
     dsFly.tblFlyDataTable _m = _mds.tblFly; 
     _t.Fill(_m); 
     foreach (DataRow _row in _m.Rows) 
     { 
      cbFly.Items.Add(_row["FlyID"].ToString()+"-"+_row["FlyName"].ToString() + "-" + _row["FlyDirection"].ToString() + "-" + _row["FlyDateTime"].ToString()); 
     } 
     _Thread.Abort(); 
     timer1.Enabled = false; 
     WaitPanel.Visible = false; 
} 

इस तरह Form_Load समारोह में है;

{ 
    _Thread = new System.Threading.Thread(new System.Threading.ThreadStart(ShowAllFly)); 
    _Thread.Start(); 
    _Thread.Priority = System.Threading.ThreadPriority.Normal; 
} 

लेकिन जब मैं इसे चलाता हूं;

ShowAllFly समारोह

cbFly.Items.Clear(); ---- HERE Gives ERROR LIKE Control.Invoke must be used to interact with controls created on a separate thread. 

समस्या क्या है में

? एक और (यूआई) सूत्र में नियंत्रण पर

उत्तर

48

विण्डोज़ फॉर्म्स में सूत्रण के दो सुनहरा नियम नहीं हैं:

  • डॉन ' नियंत्रण के "हैंडल" (आमतौर पर केवल एक यूआई थ्रेड) बनाने के अलावा किसी भी थ्रेड से किसी भी नियंत्रण गुण या विधियों (ठीक से सूचीबद्ध होने के अलावा सूचीबद्ध) के अलावा स्पर्श करें
  • समय की किसी भी महत्वपूर्ण लंबाई के लिए यूआई धागा ब्लॉक नहीं है, या आप एक अलग धागे से यूआई के साथ बातचीत करने में आवेदन अनुत्तरदायी

बना देंगे, आप करने के लिए "मार्शल" कॉल की जरूरत है यूआई थ्रेड के लिए, एक प्रतिनिधि का उपयोग करके और Control.Invoke/BeginInvoke पर कॉल करना। आप कर सकते हैं परीक्षण किया जाए या नहीं आप InvokeRequired संपत्ति का उपयोग कर Invoke कॉल करने की आवश्यकता है, लेकिन इन दिनों मैं व्यक्तिगत रूप से करते हैं बस वैसे भी यह करने के लिए - वहाँ लागू है जब आप की जरूरत नहीं है के लिए बहुत दंड नहीं है।

सी # 3 में लैम्ब्डा अभिव्यक्तियां (या सी # 2 में अज्ञात विधियां) इसे और भी सुखद बनाती हैं।

उदाहरण के लिए, आप इस्तेमाल कर सकते हैं:

cbFly.Invoke((MethodInvoker)(() => cbFly.Items.Clear())); 

सभी कोष्ठक रास्ते में एक सा मिलता है, तो आप इस तरह एक विस्तार विधि को जोड़ने के लिए, यदि आप सी # 3 का उपयोग कर रहे चाह सकते हैं:

public static void Invoke(this Control control, MethodInvoker action) 
{ 
    control.Invoke(action); 
} 

तो फिर तुम कर सकता है:

cbFly.Invoke(() => cbFly.Items.Clear()); 

जो एक अच्छा सौदा सरल है। आम तौर पर आप प्रतिनिधि के भीतर पहुंचने के लिए आवश्यक किसी भी चर को कैप्चर करके MethodInvoker का उपयोग करके दूर हो सकते हैं।

अधिक जानकारी के लिए my threading tutorial या Joe Albahari's देखें। अपने स्वयं के धागे पर वास्तव में, के बावजूद यह पीछे अन्य कॉल होने -

एक माध्यमिक मामले के रूप में, मैं तुम्हें Thread.Abort उपयोग कर रहे हैं। क्यूं कर? किसी भी धागे को अन्य अपने आप से "केवल आपातकालीन स्थिति" कॉल कॉल (जिसे आम तौर पर ऐप को अनलोड किए जाने के बाद किया जाना चाहिए) को छोड़ना और मुझे अभी भी काम करने के लिए मौजूदा थ्रेड को रद्द करने का कोई कारण नहीं दिख रहा है बाद में ...

6

इंटरेक्शन इसलिए की तरह लागू किया जा करने की जरूरत है:

public delegate void ProcessResultDelegate(string result); 
void ProcessResult(string result) 
{ 
    if (textBox1.InvokeRequired) 
    { 
     var d = new ProcessResultDelegate(ProcessResult); 
     d.Invoke(result); 
    } 
    else 
    { 
     textBox1.Text = result; 
    } 
} 
+3

अच्छा समाधान; बाइट मैं अपने आप को रोलिंग (और बनाए रखने) की बजाय ढांचे से 'एक्शन ' का उपयोग करने की सलाह दूंगा। –

+0

हाँ .. यह करने के लिए यह काफी मानक तरीका है। इसका जरूरी कारण यह है कि textBox1.Text केवल उस थ्रेड पर बदला जा सकता है जिसमें टेक्स्टबॉक्स बनाया गया था - आक्रमण करना उस थ्रेड पर वापस जाने के लिए उपयोग की जाने वाली प्रक्रिया है। –

+0

@ फ़्रेड्रिक: आप सही हैं, लेकिन इस उदाहरण को अधिकतर बार देखा जाता है, क्योंकि यह लंबे समय तक रहा है। या तो विधि काम करेगा। –

3

मुझे हमेशा इस विशेष मुद्दे पर this article सहायक पाया गया है।

अपने उदाहरण में, आप उस थ्रेड से विभिन्न नियंत्रणों को संशोधित करने का प्रयास कर रहे हैं जो नियंत्रण नहीं बनाते हैं। इस मुद्दे को अपने उदाहरण दिए गए चारों ओर पाने के लिए, यह बजाय (यह मानते हुए कि ShowAllFly() विधि अपने फार्म पर एक विधि है) कार्य करें:

public void ShowAllFly() 
{ 
    Invoke((MethodsInvoker) delegate { 
     cbFly.Items.Clear(); 
     cbFly.Items.Add("Uçuş Seçiniz..."); 
     dsFlyTableAdapters.tblFlyTableAdapter _t = 
      new KTHY.dsFlyTableAdapters.tblFlyTableAdapter(); 
     dsFly _mds = new dsFly(); 
     _mds.EnforceConstraints = false; 
     dsFly.tblFlyDataTable _m = _mds.tblFly; 
     _t.Fill(_m); 
     foreach (DataRow _row in _m.Rows) 
     { 
      cbFly.Items.Add(_row["FlyID"].ToString() + "-" + 
          _row["FlyName"].ToString() + "-" + 
          _row["FlyDirection"].ToString() + "-" + 
          _row["FlyDateTime"].ToString()); 
     } 
     //_Thread.Abort(); // WHY ARE YOU TRYING TO DO THIS? 
     timer1.Enabled = false; 
     WaitPanel.Visible = false; 
    }); 
} 

बस बिंदु @Jon स्कीट बनाया पर जोर देना, मैं बाहर टिप्पणी की है धागे को रद्द करने के लिए कॉल। धागा अपने समझौते का अंत होगा। इस फैशन में इसे निरस्त करने का कोई कारण नहीं है।

+1

आपका सर्वश्रेष्ठ मैट है। धन्यवाद। यह बहुत अच्छा काम करता है। – atromgame

+0

चूंकि वह सबसे अच्छा है, इसलिए मैंने उसे एक उपरांत दिया, जो मेरे सामने कोई भी नहीं था (संकेत, इशारा)। –

0

इसे आमंत्रित किया जाना चाहिए ... लेकिन आवेदक को अभी भी मुख्य धागे का इंतजार करना है, मेरा मतलब है कि आपको इस तरह से त्रुटि नहीं मिलती है, लेकिन यदि आप एक ही समय में एक से अधिक प्रक्रियाएं करना चाहते हैं तो यह बेहद कम काम नहीं कर रहा है एक धागा

Thread thread = new Thread(new delegate_method(method));//you must create delegate before 
thread.start(); 
Thread thread2 = new Thread(new delegate_method(method2));//you must create delegate before 
thread.start(); 

दो हैंडल प्रक्रिया एक ही समय

void method() 
{ 
//do something here -- working background Remember can not control any UI control from here 
finish_thread() 
} 

void method2() 
{ 
//do something here -- working background Remember can not control any UI control from here 
finish_thread() 
} 

void finish_thread() 
{ 
if(invoke.Required) 
{ 
//Here you have to call delegate method here with UI 
BeginInvoke(new delegate_method(finish_thread)); 
} 
else 
{ 
//Now you can control UI thread from here and also you finished background work 
//Do something working with UI thread 
textBox.Text = ""; 
} 
} 
संबंधित मुद्दे