MethodInfo mi = typeof(NotifyIcon).GetMethod("ShowContextMenu", BindingFlags.Instance | BindingFlags.NonPublic);
mi.Invoke(notify, null);这将引发以下异常:
{"Exception has been thrown by the target of an invocation."}
有以下内部异常:
"Cross-thread operation not valid: Control '' accessed from a thread other than the thread it was created on."
如果我注释掉了一行为上下文菜单项设置图像的代码,那么它就会停止抛出异常。
有什么想法吗?
发布于 2010-06-15 22:03:44
您正在更新创建UI控件的线程以外的线程上的UI控件。这是不允许的。
在常规代码中,可以使用Control.InvokeRequired属性。
假设你有一个有两个按钮和两个标签的表单,这里是如何从另一个线程进行更新的:
private void button1_Click(object sender, EventArgs e)
{
//force execution on another thread
new Thread(updateLabelThreaded).Start();
}
private void button2_Click(object sender, EventArgs e)
{
//force execution on another thread
new Thread(updateLabelReflect).Start();
}
private void updateLabelThreaded()
{
if (!label1.InvokeRequired)
{
//if we are on the correct thread, do a trivial update
label1.Text = "something";
}
else
{
//else invoke the same method, on the UI thread
Invoke(new Action(updateLabelThreaded), null);
}
}
private void updateLabelReflect()
{
Control ctrl = label2;
PropertyInfo pi = typeof (Label).GetProperty("InvokeRequired");
bool shouldInvoke = (bool) pi.GetValue(ctrl, null);
if (!shouldInvoke)
{
//if we are on the correct thread, reflect whatever is neccesary - business as usual
PropertyInfo txtProp = typeof (Label).GetProperty("Text");
txtProp.SetValue(ctrl, "Something 2", null);
}
else
{
//else invoke the same method, on the UI thread
Invoke(new Action(updateLabelReflect), null);
}
}发布于 2010-06-15 22:04:13
您可能会混淆MethodInfo的Invoke方法(它只调用当前线程上的委托)和Control.Invoke (它调用UI线程上的委托)。
如果尝试从正确的UI线程以外的线程访问UI元素,则会出现此异常。
基本上,您需要在UI线程上执行此代码。
你为什么要通过反射而不是直接调用ShowContextMenu呢?您可能只需要类似于(假设C# 3)的内容:
MethodInvoker action = () => notify.ShowContextMenu();
someControl.Invoke(action);发布于 2010-06-15 22:04:28
不能从非UI线程调用UI方法。我建议使用TaskScheduler.FromCurrentSynchronizationContext来封送对UI线程的调用。
https://stackoverflow.com/questions/3045845
复制相似问题