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."
如果我注释掉一行代码来设置上下文菜单条目的图像,那么它就会停止抛出异常。
有什么想法吗?
答案 0 :(得分:0)
您正在更新创建它们的线程以外的线程上的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);
}
}
答案 1 :(得分:0)
您可能会混淆Invoke
MethodInfo
方法,它只调用当前线程上的委托,Control.Invoke
调用UI线程上的委托。
如果您尝试从正确的UI线程以外的线程访问UI元素,则会出现此异常。
基本上你需要在UI线程上执行这段代码。
您是否有任何理由试图通过反射而不是直接调用ShowContextMenu
?你可能只需要(假设C#3):
MethodInvoker action = () => notify.ShowContextMenu();
someControl.Invoke(action);
答案 2 :(得分:0)
您无法从非UI线程调用UI方法。我建议使用TaskScheduler.FromCurrentSynchronizationContext
封送对UI线程的调用。