Reputation: 36617
So, maybe I misunderstood the usage of Func but
Func<ComboBox, string> getCurrentValue = s => s.SelectedValue.ToString();
Creates a Thread Error when calling getCurrentValue(cb_message_type)
from my Workerthread.
Whats the best solution to get the Selected Value of the Combobox?
Many thanks,
rAyt
Edit
MSDN
"The underlying type of a lambda expression is one of the generic Func delegates. This makes it possible to pass a lambda expression as a parameter without explicitly assigning it to a delegate."
Upvotes: 0
Views: 1483
Reputation: 81159
If the thread will simply be reading the ComboBox, the best option if practical is probably to have an event handler on the thread which grabs the ComboBox value any time it changes, and then exposes that value via property which can be read from any thread.
Upvotes: 0
Reputation: 115741
Generally speaking, you cannot access UI controls from a thread other than that they were created on. To overcome that, you'll either have to check ISynchronizeInvoke.InvokeRequired
on the control in question and branch, invoke a delegate, etc. or use a SynchronizationContext
. First option is very cumbersome, whereas second one is pretty elegant:
var synchronizationContext = WindowsFormsSynchronizationContext.Current;
string currentValue = "";
synchronizationContext.Send(
() => currentValue = getCurrentValue(comboBox),
null);
Upvotes: 1
Reputation: 887413
The problem is that UI controls can only be used on the UI thread,
You need to call the Invoke
method within the other thread, like this:
Func<ComboBox, string> getCurrentValue =
s => s.Invoke(new Func<object>(() => s.SelectedValue)).ToString();
The Invoke
method takes a delegate and executes it on the UI thread.
Upvotes: 1
Reputation: 1500495
You need to call Control.Invoke
with that delegate - or make the delegate itself call it.
Using a lambda expression doesn't change the threading requirements of Windows Forms - it just makes it easier to create a delegate.
You might want to make a convenience method to do this:
// (Untested)
public static Func<TControl, TResult> WrapInvocation(Func<TControl,TResult> func)
where TControl : Control
{
return control => {
return (TResult) control.Invoke(func);
};
}
Use as:
Func<ComboBox, string> getCurrentValue = s => s.SelectedValue.ToString();
getCurrentValue = WrapInvocation(getCurrentValue);
Then you can call getCurrentValue(comboBox)
from any thread.
Upvotes: 2
Reputation: 1062770
Since windows controls have thread affinity, you have 2 options:
Since the first is trivial, I'll give an example of the second using captured variables:
object value = null;
yourCombo.Invoke((MethodInvoker) delegate {value=yourCombo.SelectedValue;});
string s = value.ToString();
Here the bits inside delegate {...}
happen on the UI thread, even if the code around it is on the worker thread. You can mix the above either inside your func, or call the entire func once you've switched threads.
Upvotes: 5