Подход Ли может быть еще более упрощен
public static void InvokeIfRequired(this Control control, MethodInvoker action)
{
// See Update 2 for edits Mike de Klerk suggests to insert here.
if (control.InvokeRequired) {
control.Invoke(action);
} else {
action();
}
}
И можно так назвать
richEditControl1.InvokeIfRequired(() =>
{
// Do anything you want with the control here
richEditControl1.RtfText = value;
RtfHelpers.AddMissingStyles(richEditControl1);
});
Нет необходимости передавать элемент управления в качестве параметра делегату. C # автоматически создает замыкание .
UPDATE
Согласно нескольким другим постерам Control
можно обобщить как ISynchronizeInvoke
:
public static void InvokeIfRequired(this ISynchronizeInvoke obj,
MethodInvoker action)
{
if (obj.InvokeRequired) {
var args = new object[0];
obj.Invoke(action, args);
} else {
action();
}
}
DonBoitnott отметил, что в отличие от Control
для интерфейса ISynchronizeInvoke
требуется массив объектов для метода Invoke
в качестве списка параметров для action
.
ОБНОВЛЕНИЕ 2
Изменения, предложенные Майком де Клерком (см. Комментарий в 1-м фрагменте кода для точки вставки):
// When the form, thus the control, isn't visible yet, InvokeRequired returns false,
// resulting still in a cross-thread exception.
while (!control.Visible)
{
System.Threading.Thread.Sleep(50);
}
См. Комментарий ToolmakerSteve ниже для беспокойства по поводу этого предложения.