2009-04-02 7 views
36

मुझे पता है कि इस सवाल का पहले कहा गया है, लेकिन मैं के लिए एक रास्ता तलाश कर रहा हूँ:किसी भी क्रॉस-थ्रेडेड कोड को आमंत्रित करने का सबसे अच्छा तरीका?

  1. सुरक्षित पार पिरोया कोड के निर्माण को कारगर बनाने के।
  2. किसी भी स्थिति में इस कोड का पुन: उपयोग करें (कोई विंडोज फॉर्म संदर्भ नहीं)।

यहां मेरे पास अभी तक है, लेकिन मैं विंडोज फॉर्म संदर्भों को हटाना चाहता हूं। कोई विचार?

SafeInvoke _safeInvoker = new SafeInvoke(); 
void SafeClearItems() 
{ 
    _safeInvoker.Invoke(delegate 
     { 
      listView1.Items.Clear(); 
     }); 
} 

मैं कैसे SafeInvoke कक्षा में System.Windows.Forms.Control हटाने, लेकिन एक ही कार्यक्षमता रखने होगा:

public delegate void SafeInvokeDelegate(System.Action action); 
public class SafeInvoke 
{ 
    private readonly System.Windows.Forms.Control _threadControl; 

    public SafeInvoke() 
    { 
     _threadControl = new System.Windows.Forms.Control(); 
    } 

    public void Invoke(System.Action action) 
    { 
     if (_threadControl.InvokeRequired) 
      _threadControl.Invoke(new SafeInvokeDelegate(Invoke), new object[] {action}); 
     else if (action != null) action(); 
    } 
} 

ऊपर वर्ग इस तरह से इस्तेमाल किया जा सकता है?

+0

ध्यान दें कि डॉक्स आसपास के आह्वान () नियंत्रण पर वास्तव में बहुत सूक्ष्म हैं।मुझे विश्वास नहीं है कि एक सामान्य वर्ग नियंत्रण के लिए पर्याप्त है क्योंकि IsHandleCreated और IsDisposed के साथ बातचीत की है (जब तक कि आप हमेशा अपने सुरक्षित इनवॉकडिलेग में उनको पहले चेक न करें)। (http://stackoverflow.com/questions/714666/) –

+0

इस कक्षा को साझा करने के लिए धन्यवाद। मेरी समस्याओं को हल करने में मेरी मदद की .. –

उत्तर

86

आप अपना कोड अधिक क्लीनर बनाने के लिए एक एक्सटेंशन विधि और लैम्बडा का भी उपयोग कर सकते हैं।

using System.ComponentModel; 
public static class ISynchronizeInvokeExtensions 
{ 
    public static void InvokeEx<T>(this T @this, Action<T> action) where T : ISynchronizeInvoke 
    { 
    if (@this.InvokeRequired) 
    { 
     @this.Invoke(action, new object[] { @this }); 
    } 
    else 
    { 
     action(@this); 
    } 
    } 
} 

तो अब आप किसी भी ISynchronizeInvoke पर InvokeEx का उपयोग करें और गुण और वर्ग को लागू करने के क्षेत्र उपयोग करने में सक्षम हो सकता है।

this.InvokeEx(f => f.listView1.Items.Clear()); 
+1

यह स्पष्ट प्रतीत हो सकता है, लेकिन आपको "सिस्टम" नामस्थान –

+0

जोड़ने की भी आवश्यकता है यह एक शानदार विचार है। मैंने इसे वीबीनेट में किया और सुब्रौटाइन/फंक्शंस/विदपैम्स/बिना पैराम्स के लिए 4 ओवरलोड भी हैं। वीबीनेट जेनेरिक प्रकारों का अनुमान लगाने में सक्षम है। – Eyal

+6

क्यों न केवल 'सूची दृश्य 1। इन्वोकएक्स (एलवी => lv.Items.Clear()); '? – jgauffin

10

Control के बजाय ISynchronizeInvoke का उपयोग करें। यह इंटरफेस है कि ControlInvoke/BeginInvoke/EndInvoke/InvokeRequired के साथ लागू करता है।

एक विकल्प SynchronizationContext.Current का उपयोग करना है - जो BackgroundWorker उपयोग करता है, मुझे विश्वास है।

+0

क्या आप एक कोड उदाहरण दिखा सकते हैं? :-) ISynchronizeInvoke को कार्यान्वित करने के लिए BeginInvoke, आदि की आवश्यकता है, और थकाऊ हो सकता है। – CLaRGe

+0

ऐसा लगता है जैसे ISynchronizeInvoke केवल नियंत्रण कक्षा द्वारा लागू किया गया है। यह विंडोज फॉर्म निर्भरता से छुटकारा पाने के लिए एक तरह की तरह नहीं दिखता है। – XOR

+0

कोई कोड उदाहरण आवश्यक है। आप System.Windows.Forms.Control System.ComponentModel.ISynchronizeInvoke के साथ बस प्रतिस्थापित करें। – Samuel

4

यहां यह वीबीनेट में है, जो सैमुअल के उत्तर के समान ही है। मेरे पास चार ओवरलोड हैं, चाहे आप एक सबराउटिन या फ़ंक्शन चाहते हों और चाहे कोई पैरामीटर हो या नहीं। अधिक पैरामीटर के लिए अधिक अधिभार जोड़ना आसान होगा। वीबी.Net प्रकारों का अनुमान लगाने में सक्षम है।

Module ISynchronizeInvokeExtensions 
    Public Delegate Function GenericLambdaFunctionWithParam(Of InputType, OutputType)(ByVal input As InputType) As OutputType 
    Private Delegate Function InvokeLambdaFunctionCallback(Of InputType, OutputType)(ByVal f As GenericLambdaFunctionWithParam(Of InputType, OutputType), ByVal input As InputType, ByVal c As System.ComponentModel.ISynchronizeInvoke) As OutputType 
    Public Function InvokeEx(Of InputType, OutputType)(ByVal f As GenericLambdaFunctionWithParam(Of InputType, OutputType), ByVal input As InputType, ByVal c As System.ComponentModel.ISynchronizeInvoke) As OutputType 
     If c.InvokeRequired Then 
      Dim d As New InvokeLambdaFunctionCallback(Of InputType, OutputType)(AddressOf InvokeEx) 
      Return DirectCast(c.Invoke(d, New Object() {f, input, c}), OutputType) 
     Else 
      Return f(input) 
     End If 
    End Function 

    Public Delegate Sub GenericLambdaSubWithParam(Of InputType)(ByVal input As InputType) 
    Public Sub InvokeEx(Of InputType)(ByVal s As GenericLambdaSubWithParam(Of InputType), ByVal input As InputType, ByVal c As System.ComponentModel.ISynchronizeInvoke) 
     InvokeEx(Of InputType, Object)(Function(i As InputType) As Object 
              s(i) 
              Return Nothing 
             End Function, input, c) 
    End Sub 

    Public Delegate Sub GenericLambdaSub() 
    Public Sub InvokeEx(ByVal s As GenericLambdaSub, ByVal c As System.ComponentModel.ISynchronizeInvoke) 
     InvokeEx(Of Object, Object)(Function(i As Object) As Object 
             s() 
             Return Nothing 
            End Function, Nothing, c) 
    End Sub 

    Public Delegate Function GenericLambdaFunction(Of OutputType)() As OutputType 
    Public Function InvokeEx(Of OutputType)(ByVal f As GenericLambdaFunction(Of OutputType), ByVal c As System.ComponentModel.ISynchronizeInvoke) As OutputType 
     Return InvokeEx(Of Object, OutputType)(Function(i As Object) f(), Nothing, c) 
    End Function 
End Module 

उपयोग (एक BackgroundWorker में इस चलाने):

InvokeEx(Sub(x As String) Me.Text = x, "foo", Me) 'set form title to foo 
    InvokeEx(AddressOf MsgBox, Me.Text, Me) 
    InvokeEx(Sub() Me.Text &= "!", "foo", Me) 'append "!" to form title 
    InvokeEx(AddressOf MsgBox, Me.Text, Me) 
    Dim s As String = InvokeEx(Function() Me.Text, Me) & "bar" 'get form title to backgorundworker thread 
    InvokeEx(AddressOf MsgBox, s, Me) 'display the string from backgroundworker thread 
+0

हाय। मैं बड़ी सफलता के साथ उपरोक्त कोड का उपयोग कर रहा हूं, लेकिन मैंने कुछ कार्यक्रमों पर अपने कार्यक्रम का परीक्षण किया। इसने अधिकांश Win XP कंप्यूटरों पर सही तरीके से काम किया है, जिन पर मैंने इसका परीक्षण किया है, लेकिन उनमें से एक पर मुझे निम्न त्रुटि मिलती है: "कमॉम भाषा रनटाइम एक अवैध प्रोग्राम का पता चला"। क्या आप जानते हैं कि इसे कैसे हल करें? मैं .NET ढांचे V2 का उपयोग कर रहा हूँ। – Johan

+0

सीएलआर को अपग्रेड करने का प्रयास करें? मुझे लगता है कि सब लैम्ब्डा केवल .Net 4 द्वारा समर्थित है, इससे पहले कि केवल समारोह लैम्ब्डा था। – Eyal

+0

यह सैमुअल के जवाब के समान नहीं दिखता है। आप प्रतिनिधि बना रहे हैं। वह प्रतिनिधियों के बजाय लैम्ब्डा का उपयोग करता है। मैं वीबी कोड पोस्ट करूंगा जो मैं अपने उत्तर में उपयोग करता हूं। –

2

यहाँ शमूएल का जवाब है कि मैं का उपयोग करने के वीबी बराबर कोड है। ध्यान दें कि मेरे पास वास्तव में 2 एक्सटेंशन फ़ंक्शन हैं, लेकिन मुझे स्वीकार करना होगा कि मुझे नहीं पता कि वे वहां क्यों हैं। मैंने अपने सी # संस्करण साल पहले (शायद इस साइट से) की प्रतिलिपि बनाई थी और इसमें दोनों एक्सटेंशन फ़ंक्शन थे, लेकिन किस कारण से, मैं पूरी तरह से समझ नहीं पा रहा हूं। मैंने बस इसकी प्रतिलिपि बनाई और इसका उपयोग कैसे किया, और मैं इन जटिल कार्यों के साथ 'हुड के नीचे' पर जाने वाले सभी को समझता हूं।

#Const System_ComponentModel = True 
#Const System_Drawing = False 

Option Compare Binary 
Option Explicit On 
Option Strict On 

Imports System.Collections 
Imports System.Runtime.CompilerServices ' for Extension() attribute 
Imports System.Text 
#If System_ComponentModel Then 
Imports System.ComponentModel 
#End If 
#If System_Drawing Then 
Imports System.Drawing 
#End If 

Public Module MyExtensions 

    ' other #Region blocks are removed. i use many in my Extensions 
    ' module/class. the below code is only the 2 relevant extension 
    ' for this 'SafeInvoke' functionality. but i use other regions 
    ' such as "String extensions" and "Numeric extensions". i use 
    ' the above System_ComponentModel and System_Drawing compiler 
    ' directives to include or exclude blocks of code that i want 
    ' to either include or exclude in a project, which allows me to 
    ' easily compare my code in one project with the same file in 
    ' other projects to syncronise new changes across projects. 
    ' you can scrap pretty much all the code above, 
    ' but i'm giving it here so you see it in the full context. 

    #Region "ISynchronizeInvoke extensions" 

    #If System_ComponentModel Then 

     <Extension()> 
     Public Function SafeInvoke(Of T As ISynchronizeInvoke, TResult)(isi As T, callFunction As Func(Of T, TResult)) As TResult 
      If (isi.InvokeRequired) Then 
       Dim result As IAsyncResult = isi.BeginInvoke(callFunction, New Object() {isi}) 
       Dim endresult As Object = isi.EndInvoke(result) 
       Return DirectCast(endresult, TResult) 
      Else 
       Return callFunction(isi) 
      End If 
     End Function 

     ''' <summary> 
     ''' This can be used in VB with: 
     ''' txtMyTextBox.SafeInvoke(Sub(d) d.Text = "This is my new Text value.") 
     ''' or: 
     ''' txtMyTextBox.SafeInvoke(Sub(d) d.Text = myTextStringVariable) 
     ''' </summary> 
     ''' <typeparam name="T"></typeparam> 
     ''' <param name="isi"></param> 
     ''' <param name="callFunction"></param> 
     ''' <remarks></remarks> 
     <Extension()> 
     Public Sub SafeInvoke(Of T As ISynchronizeInvoke)(isi As T, callFunction As Action(Of T)) 
      If isi.InvokeRequired Then 
       isi.BeginInvoke(callFunction, New Object() {isi}) 
      Else 
       callFunction(isi) 
      End If 
     End Sub 

    #End If 

    #End Region 

    ' other #Region blocks are removed from here too. 

End Module 

और सी # संस्करण है:

#define System_ComponentModel 
#undef System_Drawing 

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 

#if System_ComponentModel 
using System.ComponentModel; 
#endif 
#if System_Drawing 
using System.Drawing; 
#endif 

namespace MyCompany.Extensions 
{ 
    static partial class MyExtensions 
    { 

     // other #Region blocks are removed. i use many in my Extensions 
     // module/class. the below code is only the 2 relevant extension 
     // for this 'SafeInvoke' functionality. but i use other regions 
     // such as "String extensions" and "Numeric extensions". i use 
     // the above System_ComponentModel and System_Drawing compiler 
     // directives to include or exclude blocks of code that i want 
     // to either include or exclude in a project, which allows me to 
     // easily compare my code in one project with the same file in 
     // other projects to syncronise new changes across projects. 
     // you can scrap pretty much all the code above, 
     // but i'm giving it here so you see it in the full context. 

     #region ISynchronizeInvoke extensions 
#if System_ComponentModel 

     public static TResult SafeInvoke<T, TResult>(this T isi, Func<T, TResult> callFunction) where T : ISynchronizeInvoke 
     { 
      if (isi.InvokeRequired) 
      { 
       IAsyncResult result = isi.BeginInvoke(callFunction, new object[] { isi }); 
       object endResult = isi.EndInvoke(result); return (TResult)endResult; 
      } 
      else 
       return callFunction(isi); 
     } 

     /// <summary> 
     /// This can be used in C# with: 
     /// txtMyTextBox.SafeInvoke(d => d.Text = "This is my new Text value."); 
     /// or: 
     /// txtMyTextBox.SafeInvoke(d => d.Text = myTextStringVariable); 
     /// </summary> 
     /// <typeparam name="T"></typeparam> 
     /// <param name="isi"></param> 
     /// <param name="callFunction"></param> 
     public static void SafeInvoke<T>(this T isi, Action<T> callFunction) where T : ISynchronizeInvoke 
     { 
      if (isi.InvokeRequired) isi.BeginInvoke(callFunction, new object[] { isi }); 
      else 
       callFunction(isi); 
     } 

#endif 
     #endregion 

     // other #Region blocks are removed from here too. 

    } // static class MyExtensions 

} // namespace 

मुबारक कोडिंग!

+1

बहुत उपयोगी; विशेष रूप से विस्तार जो रिटर्न परिणाम के साथ काम करता है। +1 – MiBol

+0

धन्यवाद, मैं भी बहुत थक गया। : पी –

2
अब

एक दिन यह आसान है को लागू करने जैसे कहते हैं कि हम txtVal का मूल्य उस के रूप में

lblVal.invoke((MethodInvoker)delegate{txtVal.Text = lblVal.Text;}); 

के रूप में आसान पाने के लिए एक लेबल (lblVal) आह्वान करना चाहते हैं: डी

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