Я создал приложение, которое использует плагины. Плагин содержит ToolStrip, который я хочу добавить в основную панель контейнера ToolStrip (в классе Form1). Это просто container.TopToolStripPanel.Controls.Add(plugin.PluginToolStrip;
, но если я хочу запускать код плагинов в отдельном потоке, это не так просто. (Я использую многопоточность для простого способа выгрузки плагина, мне нужно только убить поток плагина и удалить ToolStrip из основной формы)
Я отключил CheckForIllegalCrossThreadCalls = false;
, чтобы разрешить неиспользование Invoke void. Но когда я хочу запустить container.TopToolStripPanel.Controls.Add(plugin.PluginToolStrip);
из другого потока, программа выдает ArgumentException
и говорит, что я не могу этого сделать.
Итак, как я могу создать архитектуру плагинов с возможностью убивать потоки плагинов? (Я хочу дать пользователю возможность легкого управления плагинами)
Я декомпилировал 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();
}
}
у нас есть только get, и он внутренний :(
Что я могу сделать? У Вас есть какие-то предложения? Спасибо и извините за мой плохой английский...
SafeInvoke
, является нет-нет и приведет к неприятным сбоям и трудным для поиска ошибкам. Этот принцип и правило применимы не только к C#/Windows, но и к Java, Android, iOS и т. д. Вам следует изучить перестройку механизмов плагинов, чтобы позволить использовать вызовы перекрестных потоков таким образом, который способствует плавности пользовательского интерфейса. - person t0mm13b   schedule 04.04.2017