我創建了一個使用插件的應用程序。插件包含我想添加到主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