我创建了一个使用插件的应用程序。插件包含我想添加到主ToolStrip容器面板(在Form1类中)的ToolStrip。这很容易container.TopToolStripPanel.Controls.Add(plugin.PluginToolStrip;
,但是如果我想在单独的线程中运行插件代码,那么它并不容易。 (我使用多线程简单的方式来卸载插件,我只需要杀死插件线程,并从主窗体中删除ToolStrip)如何将Control从另一个线程添加到Control,而无需调用?
我禁用了CheckForIllegalCrossThreadCalls = false;
以允许不使用Invoke void。但是当我想从另一个线程运行container.TopToolStripPanel.Controls.Add(plugin.PluginToolStrip);
时,程序会抛出ArgumentException
,并说我无法做到这一点。
那么,我该如何创建具有杀死插件线程的插件架构呢? (我想给管理插件的简便方法用户可能)
我decompilled System.Windows.Forms.dll中,看看它抛出异常,我看到:
/// <summary>Adds the specified control to the control collection.</summary>
/// <param name="value">The <see cref="T:System.Windows.Forms.Control" /> to add to the control collection. </param>
/// <exception cref="T:System.Exception">The specified control is a top-level control, or a circular control reference would result if this control were added to the control collection. </exception>
/// <exception cref="T:System.ArgumentException">The object assigned to the <paramref name="value" /> parameter is not a <see cref="T:System.Windows.Forms.Control" />. </exception>
public virtual void Add(Control value)
{
if (value == null)
{
return;
}
if (value.GetTopLevel())
{
throw new ArgumentException(SR.GetString("TopLevelControlAdd"));
}
if (this.owner.CreateThreadId != value.CreateThreadId)
{
throw new ArgumentException(SR.GetString("AddDifferentThreads")); //here!
}
/* [...] */
}
那么我想,如果我可以改变this.owner.CreateThreadId
,那么我将能够通过这个如果(if (this.owner.CreateThreadId != value.CreateThreadId)
),和程序不会抛出异常。上线6315我看到这个代码:
internal int CreateThreadId
{
get
{
if (this.IsHandleCreated)
{
int num;
return SafeNativeMethods.GetWindowThreadProcessId(new HandleRef(this, this.Handle), out num);
}
return SafeNativeMethods.GetCurrentThreadId();
}
}
我们只拿到了,它的内部:(
我能做些什么你有什么建议,谢谢,我的英语不好对不起......?
简短答案是否定的,从一个线程更新一个UI,而不使用像SafeInvoke这样的安全交叉线程机制是* no no *,并且会产生令人不快的故障并且很难找到错误。原则和规则不仅适用于C#/ Windows,它适用于Java,Android,iOS等。您应该考虑重新构建插件机制,以便能够以有利于UI平滑的方式使用跨线程调用。 – t0mm13b