[英]C# Func Delegate throws Thread Exception
So, maybe I misunderstood the usage of Func but 所以,也许我误解了Func的用法,但是
Func<ComboBox, string> getCurrentValue = s => s.SelectedValue.ToString();
Creates a Thread Error when calling getCurrentValue(cb_message_type)
from my Workerthread. 从我的Workerthread调用
getCurrentValue(cb_message_type)
时创建线程错误。 Whats the best solution to get the Selected Value of the Combobox? 什么是获得组合框选定值的最佳解决方案?
Many thanks, 非常感谢,
rAyt A
Edit 编辑
MSDN 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." “ lambda表达式的基础类型是泛型Func委托之一。这使得可以将lambda表达式作为参数传递而无需显式将其分配给委托。”
Since windows controls have thread affinity, you have 2 options: 由于Windows控件具有线程关联性,因此您有2个选项:
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. 这里,
delegate {...}
的位发生在UI线程上,即使它周围的代码在工作线程上也是如此。 You can mix the above either inside your func, or call the entire func once you've switched threads. 您可以在函数内部混合以上内容,也可以在切换线程后调用整个函数。
You need to call Control.Invoke
with that delegate - or make the delegate itself call it. 您需要使用该委托调用
Control.Invoke
或让委托本身调用它。 Using a lambda expression doesn't change the threading requirements of Windows Forms - it just makes it easier to create a delegate. 使用lambda表达式不会更改Windows Forms的线程要求,而只是使创建委托变得更加容易。
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. 然后,您可以从任何线程调用
getCurrentValue(comboBox)
。
The problem is that UI controls can only be used on the UI thread, 问题是UI控件只能在UI线程上使用,
You need to call the Invoke
method within the other thread, like this: 您需要在另一个线程中
Invoke
方法,如下所示:
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. Invoke
方法接受一个委托,并在UI线程上执行它。
Generally speaking, you cannot access UI controls from a thread other than that they were created on. 通常,您不能从创建线程的线程之外的线程访问UI控件。 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
. 为了克服这个问题,您要么必须在有问题和分支的控件上检查
ISynchronizeInvoke.InvokeRequired
,要么调用委托等,或者使用SynchronizationContext
。 First option is very cumbersome, whereas second one is pretty elegant: 第一个选择非常麻烦,而第二个选择则非常优雅:
var synchronizationContext = WindowsFormsSynchronizationContext.Current;
string currentValue = "";
synchronizationContext.Send(
() => currentValue = getCurrentValue(comboBox),
null);
如果线程将仅读取ComboBox,则可行的最佳选择是在线程上有一个事件处理程序,该事件处理程序在更改时随时获取ComboBox值,然后通过可从任何线程读取的属性公开该值。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.