2009-02-20 9 views
23

W tym artykule:Najkrótsza droga do napisać metodę dostępu wątku bezpieczny do Windows Forms sterowania

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

Autorka wykorzystuje następujące metody wykonywania połączeń thread-safe do systemu Windows kontrolę Forms:

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; 
    } 
} 

Czy jest krótszy sposób na osiągnięcie tego samego?

Odpowiedz

32

C# 3.0 i po:

metodę rozszerzenia na ogół być droga, ponieważ jesteś zawsze będzie chciał, aby wykonać działanie na realizację ISynchronizeInvoke interface, że to dobry wybór projektu.

Możesz również skorzystać z anonymous methods (zamknięć), aby uwzględnić fakt, że nie wiesz, jakie parametry przekazać do metody rozszerzenia; zamknięcie uchwyci stan wszystkiego, czego potrzebuje.

// 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[] { }); 
} 

Byłbyś wtedy nazwać tak:

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

Tutaj, zamknięcie jest na parametrze text, że stan jest rejestrowany i przekazywany jako część Action delegate przekazany do metody rozszerzenia.

Przed C# 3.0:

Nie masz luksus wyrażeń lambda, ale nadal można uogólniać kod. To niemal tak samo, ale nie metoda rozszerzenie:

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[] { }); 
} 

A potem to nazwać z metody anonimowej składnię:

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

Tak, działa świetnie, jedyne co musisz zauważyć to to, że musisz uwzględnić: using System.ComponentModel; i używając System; –

+0

Wiem, że jest dość stary, ale wciąż pojawia się w górnej części wyszukiwania dla tego rozwiązania ... Problem polega na tym, że zakładasz, że klasa nadrzędna jest statyczna. Nie można dodać statycznego rozszerzenia do zwykłej klasy. Większość formularzy/WPF zawierających interfejs, do którego chcesz uzyskać dostęp, to regularne zajęcia z instancjami. W takich przypadkach pozostaje ci jedyna opcja anonimowego delegata, jak pokazano poniżej. –

+0

@JohnSuit Na pewno możesz dodać metodę statyczną do "zwykłej" klasy. Wersja post 3.0 jest metodą rozszerzenia i pojawiłaby się jako metoda instancji. Wersja pre-3.0 nie musi żyć na klasie, może żyć na innej klasie, lub możesz uczynić metodę instancją, jeśli naprawdę potrzebujesz (ale nie, ponieważ możesz dodać statyczną metodę). – casperOne

3

Edycja: należy wspomnieć, nie uważam, że jest to najlepsza praktyka

Jeśli używasz 3.5 można dokonać metodę rozszerzenia do skutku:

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

to jest w zasadzie podjętej od: Here

następnie użyć go lubię:

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

Oczywiście zmodyfikuj rozszerzenie itp. Dla twoich zwyczajów.

8

1) przy użyciu anonimowych delegata

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

2) Podejście AOP

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

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

3) Używanie wyrażeń lambda (zaznaczonych przez innych).

1

Może to być oczywiste dla większości, ale można wziąć zaakceptowane odpowiedź i dodać inną metodę, jeśli chcesz pobrać wartość ...

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[] { }); 
} 

Kiedyś to niedawno, aby uzyskać uchwyt w formie sposób bezpieczny dla wątków ...

var handle = f.SynchronizedFunc(() => f.Handle); 
Powiązane problemy