2008-09-29 10 views
7

मेरे पास एक Winforms एप्लिकेशन है, समस्या को थ्रेडिंग के साथ करना है। चूंकि मैं 'MyCustomCode() को कॉल कर रहा हूं जो एक नया धागा बनाता है, और विधि ' SomeMethod() 'को कॉल करता है जो तब MessageBox.Show (...) तक पहुंचता है।Winforms थ्रेडिंग समस्या, दूसरा थ्रेड 1 मुख्य मुख्य रूपों को नियंत्रित नहीं कर सकता

समस्या को थ्रेडिंग के साथ करना है, क्योंकि नव निर्मित धागा को किसी अन्य थ्रेड पर बनाए गए नियंत्रण को एक्सेस करने का प्रयास कर रहा है।

पार धागा आपरेशन मान्य नहीं: नियंत्रण 'TestForm' धागा उस पर बनाया गया था के अलावा किसी अन्य धागे से पहुँचा

मैं त्रुटि हो रही है।

public TestForm() 
{ 
    InitializeComponent(); 


    // custom code 
    // 
    MyCustomCode(); 


} 

public void SomeMethod() 
{ 

    // ***** This causes an error **** 

    MessageBox.Show(this, 
     ex.Message, 
     "Error", 
     MessageBoxButtons.OK, 
     MessageBoxIcon.Error 
    ); 
} 



private void InitializeAutoUpdater() 
{ 
     // Seperate thread is spun to keep polling for updates 
     ThreadStart ts = new ThreadStart(SomeMethod); 
     pollThread = new Thread(ts); 
     pollThread.Start(); 
} 

अद्यतन

आप इस उदाहरण http://www.codeproject.com/KB/cs/vanillaupdaterblock.aspx को देखें, तो विधि CheckAndUpdate MessageBox.Show (..) बुला रहा है कि क्या मेरी समस्या है। मैंने सोचा होगा कि कोड जाने के लिए अच्छा था!

मजेदार बात यह है कि यह कोड शुक्रवार को ठीक काम कर रहा था ???

+0

ऐसा इसलिए हो सकता है क्योंकि मैंने .NET 3.5 स्थापित किया था? क्या यह 3.5 'फीचर' है? मुझे शक है लेकिन यह एकमात्र स्पष्टीकरण है! –

+0

(मैंने इसे हाल ही में स्थापित किया है ..) –

उत्तर

9

आप एकाधिक धागे से यूआई तत्वों को acces नहीं कर सकते हैं।

इसे हल करने का एक तरीका यह है कि यूआई तत्वों (जैसे संदेश बॉक्स) का उपयोग करने वाले फ़ंक्शन में एक प्रतिनिधि के साथ नियंत्रण की Invoke विधि को कॉल करना है। समथिंग की तरह:

public delegate void InvokeDelegate(); 

public void SomeMethod() 
{ 

    button1.Invoke((InvokeDelegate)doUIStuff); 


} 


void doUIStuff() 
{ 
      MessageBox.Show(this, 
       ex.Message, 
       "Error", 
       MessageBoxButtons.OK, 
       MessageBoxIcon.Error 
      ); 
} 
+0

आपको जांचना चाहिए कि क्या आमंत्रण आवश्यक है, उदाहरण के लिए button1.InvokeRequired। – RickL

+0

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

0

आप नहीं उपयोग BeginInvoke, आप आह्वान का उपयोग करना चाहिए करना चाहिए, तो एक बार आपको लगता है कि समझ, आप BeginInvoke का उपयोग कर यदि वास्तव में जरूरत पर गौर कर सकते हैं।

0
'******************************************************************* 
' Get a new processor and fire it off on a new thread. 
'******************************************************************* 
fpProc = New Processor(confTable, paramFile, keyCount) 
AddHandler fpProc.LogEntry, AddressOf LogEntry_Handler 
Dim myThread As System.Threading.Thread = New System.Threading.Thread(AddressOf fpProc.ProcessEntry) 
myThread.Start() 

तो पेरेंट एप्लिकेशन में आप:

+०१२३५१६४१०
'************************************************************************* 
'  Sub: LogEntry_Handler() 
' Author: Ron Savage 
' Date: 08/29/2007 
' 
' This routine handles the LogEntry events raised by the Processor class 
' running in a thread. 
'************************************************************************* 
Private Sub LogEntry_Handler(ByVal logLevel As Integer, ByVal logMsg As String) Handles fProc.LogEntry 
writeLogMessage(logMsg); 
End Sub 

यही वह है जो मैं करता हूं।

+2

डब्ल्यूटीएफ? यह क्या है? – leppie

+0

यह इंटर प्रक्रिया संचार (इस मामले में अभिभावक के लिए धागा को संभालने के लिए इवेंट संदेश कतार का उपयोग करता है। :-) मेरे पास एक ही मूल विंडो में अपडेट भेजने वाले धागे का "अज्ञात नंबर" है। –

+0

मैं लेप्पी के साथ समझौता कर रहा हूं। – RickL

7

पार धागा अपवाद (InvalidOperationException) से बचने के लिए, यहाँ कोड पैटर्न है:

protected delegate void someGuiFunctionDelegate(int iParam); 

protected void someGuiFunction(int iParam) 
{ 
    if (this.InvokeRequired) 
    { 
     someGuiFunctionDelegate dlg = new 
      someGuiFunctionDelegate(this.someGuiFunction); 
     this.Invoke(dlg, new object[] { iParam }); 
     return; 
    } 

    //do something with the GUI control here 
} 

मैं मानता हूँ कि यह कष्टप्रद है, लेकिन यह सच है कि विंडोज़ जीयूआई नियंत्रण thread- नहीं कर रहे हैं की एक विरूपण साक्ष्य है सुरक्षित। अपवाद को कहीं या किसी झंडे से बंद कर दिया जा सकता है, लेकिन ऐसा न करें क्योंकि इससे बग खोजने में बहुत मुश्किल हो सकती है।

1

नंबर एक नियम जब बहु-थ्रेडिंग आप पूरी तरह से कार्यकर्ता थ्रेड से UI को स्पर्श नहीं कर सकते हैं। बहु-थ्रेडिंग को लागू करने के कई तरीके हैं और इसे "सही" प्राप्त करना बहुत मुश्किल है।Updating the UI from a Secondary Thread

यहाँ और एक लंबा लेख है कि में गहराई से सूत्रण की चर्चा है - -

यहाँ एक संक्षिप्त लेख है कि आप बाहर की मदद करनी चाहिए है Multi-threading in .NET

3

चीजें आप BackGroundWorker वर्ग का उपयोग कर पर गौर कर सकते सरल रखने के लिए। यह कक्षा आपके थ्रेडिंग और प्रगति अधिसूचना घटनाओं को संभालने के लिए एक ढांचा प्रदान करेगी। आपका यूई थ्रेड प्रोग्रेस इवेंट को संभालेगा और आपके द्वारा वापस भेजे गए त्रुटि संदेश को प्रदर्शित करेगा। InvokeRequired

0

चेक मैं एक पुनरावर्ती कॉल की तरह praticularly।

public delegate void InvokeDelegate(string errMessage); 

    public void SomeMethod() 
    { 
     doUIStuff("my error message"); 
    } 


    void doUIStuff(string errMessage) 
    { 
     if (button1.InvokeRequired) 
      button1.Invoke((InvokeDelegate)doUIStuff(errMessage)); 
     else 
     { 
       MessageBox.Show(this,  
        ex.Message, 
        errMessage, 
        MessageBoxButtons.OK, 
        MessageBoxIcon.Error 
       ); 
     } 
    } 
1

मैं जानता हूँ कि यह एक पुराने पोस्ट है, लेकिन मैं हाल ही में जेनरिक और विस्तार तरीकों का उपयोग कर इस समस्या का एक सुरुचिपूर्ण समाधान मिल गया। यह लेखकों के काम और कुछ टिप्पणियों का एक संयोजन है।

एक जेनेरिक पार धागा Winforms प्रवेश के लिए विधि

http://www.codeproject.com/KB/cs/GenericCrossThread.aspx

public static void Manipulate<T>(this T control, Action<T> action) where T : Control 
{ 
    if (control.InvokeRequired) 
    { 
     control.Invoke(new Action<T, Action<T>>(Manipulate), 
        new object[] { control, action }); 
    } 
    else 
    { action(control); } 
} 

यह निम्नलिखित तरीके से कहा जा सकता है, सादगी के लिए मैं एक लेबल का इस्तेमाल किया।

someLabel.Manipulate(lbl => lbl.Text = "Something"); 
संबंधित मुद्दे