2009-07-31 11 views
0

So wirft, vielleicht falsch verstanden ich die Verwendung von Func aberC# Func Delegate Thema Exception

Func<ComboBox, string> getCurrentValue = s => s.SelectedValue.ToString(); 

erstellt einen Thread Fehler beim getCurrentValue(cb_message_type) von meinem Workerthread aufrufen. Was ist die beste Lösung, um den ausgewählten Wert der Combobox zu erhalten?

Vielen Dank,
Rayt

bearbeiten
MSDN

„Der zugrunde liegende Typ eines Lambda-Ausdruck eine der generischen Func Delegierten ist. Dies macht es möglich, einen Lambda-Ausdruck übergeben als Parameter, ohne sie explizit einem Delegaten zuzuweisen. "

Antwort

5

Da Windows-Steuerelemente Threadaffinität haben, haben Sie 2 Möglichkeiten:

  1. Abfrage dieser Daten vor Ihrer Threading-Code, zum Beispiel tun es in als den Staat der Arbeiter
  2. Abfrage es im Vorbeigehen die Arbeiter über Control.Invoke

Da die erste trivial ist, werde ich ein Beispiel für die Verwendung von zweiten erfassten Variablen geben:

object value = null; 
yourCombo.Invoke((MethodInvoker) delegate {value=yourCombo.SelectedValue;}); 
string s = value.ToString(); 

Hier passieren die Bits in delegate {...} auf dem UI-Thread, auch wenn der Code um es auf dem Arbeitsthread ist. Sie können die oben genannten entweder innerhalb Ihre Funktion mischen, oder rufen Sie die gesamte Funktion, sobald Sie Threads gewechselt haben.

2

Sie müssen Control.Invoke mit diesem Delegaten aufrufen - oder den Delegaten selbst anrufen lassen. Durch die Verwendung eines Lambda-Ausdrucks werden die Threading-Anforderungen von Windows Forms nicht geändert. Es vereinfacht das Erstellen eines Delegaten.

Vielleicht möchten Sie eine bequeme Methode, um dies zu tun:

// (Untested) 
public static Func<TControl, TResult> WrapInvocation(Func<TControl,TResult> func) 
    where TControl : Control 
{ 
    return control => { 
     return (TResult) control.Invoke(func); 
    }; 
} 

Anwendung:

Func<ComboBox, string> getCurrentValue = s => s.SelectedValue.ToString(); 
getCurrentValue = WrapInvocation(getCurrentValue); 

Dann können Sie getCurrentValue(comboBox) von jedem Thread aufrufen.

1

Das Problem ist, dass UI-Steuerelemente können nur auf dem UI-Thread verwendet werden,

Sie benötigen die Invoke Verfahren in dem anderen Thread zu nennen, wie folgt aus:

Func<ComboBox, string> getCurrentValue = 
    s => s.Invoke(new Func<object>(() => s.SelectedValue)).ToString(); 

Die Invoke Methode nimmt ein Delegieren und führt es im UI-Thread aus.

1

Im Allgemeinen können Sie nicht auf Benutzeroberflächensteuerelemente aus einem anderen Thread als dem, auf dem sie erstellt wurden, zugreifen. Um das zu überwinden, müssen Sie entweder ISynchronizeInvoke.InvokeRequired auf dem betreffenden Steuerelement überprüfen und verzweigen, einen Delegaten aufrufen usw. oder SynchronizationContext verwenden.Erste Option ist sehr umständlich, während die zweite ein ziemlich elegant ist:

var synchronizationContext = WindowsFormsSynchronizationContext.Current; 
string currentValue = "";  

synchronizationContext.Send(
    () => currentValue = getCurrentValue(comboBox), 
    null); 
0

Wenn der Faden einfach die ComboBox liest, ist die beste Option, wenn praktisch ist wahrscheinlich ein Event-Handler auf dem Thread zu haben, die die ComboBox Wert packt jedes Mal, wenn es sich ändert, und dann diesen Wert über eine Eigenschaft verfügbar macht, die von jedem Thread gelesen werden kann.