2009-02-20 15 views
23

को नियंत्रित इस अनुच्छेद में:सबसे छोटा रास्ता एक विंडोज़ रूपों के लिए एक धागा सुरक्षित अभिगम विधि लिखने के लिए

http://msdn.microsoft.com/en-us/library/ms171728(VS.80).aspx

लेखक का उपयोग करता है एक Windows करने के लिए धागा सुरक्षित कॉल करने के लिए निम्न विधि नियंत्रण फॉर्म्स:

private void SetText(string text) 
{ 
    // InvokeRequired required compares the thread ID of the 
    // calling thread to the thread ID of the creating thread. 
    // If these threads are different, it returns true. 
    if (this.textBox1.InvokeRequired) 
    {  
     SetTextCallback d = new SetTextCallback(SetText); 
     this.Invoke(d, new object[] { text }); 
    } 
    else 
    { 
     this.textBox1.Text = text; 
    } 
} 

क्या एक ही चीज़ को पूरा करने का एक छोटा रास्ता है?

उत्तर

32

सी # 3.0 और बाद:

एक विस्तार विधि आम तौर पर, जाने के लिए तरीका होगा जब से तुम हमेशा एक ISynchronizeInvoke interface कार्यान्वयन पर एक काम करवाना चाहते हैं जा रहे हैं, यह एक अच्छा डिजाइन विकल्प है।

आप इस तथ्य के लिए anonymous methods (बंद) का लाभ भी ले सकते हैं कि आप यह नहीं जानते कि एक्सटेंशन विधि में कौन से पैरामीटर पास होंगे; बंद करने की आवश्यकता सब कुछ की स्थिति पर कब्जा करेगा।

// Extension method. 
static void SynchronizedInvoke(this ISynchronizeInvoke sync, Action action) 
{ 
    // If the invoke is not required, then invoke here and get out. 
    if (!sync.InvokeRequired) 
    { 
     // Execute action. 
     action(); 

     // Get out. 
     return; 
    } 

    // Marshal to the required context. 
    sync.Invoke(action, new object[] { }); 
} 

फिर आप इसे इस तरह फोन चाहते हैं:

private void SetText(string text) 
{ 
    textBox1.SynchronizedInvoke(() => textBox1.Text = text); 
} 

इधर, बंद, text पैरामीटर खत्म हो गया है कि राज्य पर कब्जा कर लिया और Action delegate विस्तार विधि के लिए पारित के हिस्से के रूप पारित कर दिया है।

से पहले सी # 3.0:

आप लैम्ब्डा अभिव्यक्ति की विलासिता नहीं है, लेकिन आप अभी भी कोड सामान्यीकरण कर सकते हैं। यह बहुत ज्यादा एक ही है, लेकिन नहीं एक विस्तार विधि:

static void SynchronizedInvoke(ISynchronizeInvoke sync, Action action) 
{ 
    // If the invoke is not required, then invoke here and get out. 
    if (!sync.InvokeRequired) 
    { 
     // Execute action. 
     action(); 

     // Get out. 
     return; 
    } 

    // Marshal to the required context. 
    sync.Invoke(action, new object[] { }); 
} 

और फिर आप यह गुमनाम विधि वाक्य रचना के साथ फोन:

private void SetText(string text) 
{ 
    SynchronizedInvoke(textBox1, delegate() { textBox1.Text = text; }); 
} 
+1

हाँ अच्छा काम करता है, केवल एक चीज आप ध्यान दें करने की आवश्यकता है कि आप शामिल करने की जरूरत है: System.ComponentModel उपयोग करते हुए; और सिस्टम का उपयोग; –

+0

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

+0

@ जॉन्स सूट आप निश्चित रूप से "नियमित" कक्षा में एक स्थिर विधि जोड़ सकते हैं। पोस्ट 3.0 संस्करण एक विस्तार विधि है, और एक उदाहरण विधि के रूप में दिखाई देगा। प्री-3.0 संस्करण को कक्षा में नहीं रहना पड़ता है, यह किसी अन्य वर्ग पर रह सकता है, या यदि आपको वास्तव में आवश्यकता है तो आप विधि को एक उदाहरण विधि बना सकते हैं (लेकिन आप तब से नहीं जब से आप एक स्थिर विधि जोड़ सकते हैं)। – casperOne

3

संपादित करें:

public static void SafeInvoke(this Control control, Action handler) { 
    if (control.InvokeRequired) { 
     control.Invoke(handler); 
    } 
    else { 
     handler(); 
    } 
} 

इस मूल रूप से लिया जाता है: मुझे लगता है मैं इस पर विचार नहीं होगा एक बेस्ट प्रैक्टिस

आप 3.5 का उपयोग कर रहे हैं, तो आप के प्रभाव के लिए एक विस्तार विधि कर सकते हैं होने के लिए उल्लेख करना चाहिए से: Here

फिर इसका इस्तेमाल चाहते:

textBox1.SafeInvoke(() => ....); 

बेशक अपने उपयोग के लिए एक्सटेंशन इत्यादि को संशोधित करें।

8

1) का उपयोग करते हुए गुमनाम प्रतिनिधि

private void SetText(string text) 
{ 
    if (this.InvokeRequired) 
    {  
     Invoke(new MethodInvoker(delegate() { 
      SetText(text); 
     })); 
    } 
    else 
    { 
     this.textBox1.Text = text; 
    } 
} 

2) एओपी दृष्टिकोण

[RunInUIThread] 
private void SetText(string text) 
{ 
    this.textBox1.Text = text; 
} 

http://weblogs.asp.net/rosherove/archive/2007/05.aspx?PageIndex=2

3) लैम्ब्डा अभिव्यक्तियों का उपयोग करना (दूसरों द्वारा उल्लिखित)।

1

यह सबसे करने के लिए स्पष्ट हो सकता है, लेकिन आप स्वीकार किए जाते हैं जवाब लेने के लिए और किसी अन्य विधि जोड़ें यदि आपने मान प्राप्त करने की आवश्यकता कर सकते हैं ...

public static T SynchronizedFunc<T>(this ISynchronizeInvoke sync, Func<T> func) 
{ 
    if (!sync.InvokeRequired) 
    { 
     // Execute the function 
     return func(); 
    } 

    // Marshal onto the context 
    return (T) sync.Invoke(func, new object[] { }); 
} 

मैं इस प्रयोग किया जाता है हाल ही में में फार्म की संभाल पाने के लिए एक धागा सुरक्षित तरीका ...

var handle = f.SynchronizedFunc(() => f.Handle); 
संबंधित मुद्दे