J'ai résolu ce problème de synchronisation pour BeginInvoke en utilisant la recommandation de Hans Passant d'attraper ObjectDisposedException. Jusqu'à présent, cela semble fonctionner. J'ai créé des méthodes d'extension de la classe Control pour faciliter cela. TryBeginInvoke tente d'invoquer sa propre méthode sur le contrôle
Si la méthode est appelée avec succès, elle vérifie si le contrôle a été éliminé. Si elle a été éliminée, elle revient immédiatement; sinon, il appelle la méthode initialement transmise en tant que paramètre à TryBeginInvoke.Le code est le suivant:
public static class ControlExtension
{
// --- Static Fields ---
static bool _fieldsInitialized = false;
static InvokeDelegateDelegate _methodInvokeDelegate; // Initialized lazily to reduce application startup overhead [see method: InitStaticFields]
static InvokeMethodDelegate _methodInvokeMethod; // Initialized lazily to reduce application startup overhead [see method: InitStaticFields]
// --- Public Static Methods ---
public static bool TryBeginInvoke(this Control control, Delegate method, params object[] args)
{
IAsyncResult asyncResult;
return TryBeginInvoke(control, method, out asyncResult, args);
}
/// <remarks>May return true even if the target of the invocation cannot execute due to being disposed during invocation.</remarks>
public static bool TryBeginInvoke(this Control control, Delegate method, out IAsyncResult asyncResult, params object[] args)
{
if (!_fieldsInitialized)
InitStaticFields();
asyncResult = null;
if (!control.IsHandleCreated || control.IsDisposed)
return false;
try
{
control.BeginInvoke(_methodInvokeDelegate, control, method, args);
}
catch (ObjectDisposedException)
{
return false;
}
catch (InvalidOperationException) // Handle not created
{
return false;
}
return true;
}
public static bool TryBeginInvoke(this Control control, MethodInvoker method)
{
IAsyncResult asyncResult;
return TryBeginInvoke(control, method, out asyncResult);
}
/// <remarks>May return true even if the target of the invocation cannot execute due to being disposed during invocation.</remarks>
public static bool TryBeginInvoke(this Control control, MethodInvoker method, out IAsyncResult asyncResult)
{
if (!_fieldsInitialized)
InitStaticFields();
asyncResult = null;
if (!control.IsHandleCreated || control.IsDisposed)
return false;
try
{
control.BeginInvoke(_methodInvokeMethod, control, method);
}
catch (ObjectDisposedException)
{
return false;
}
catch (InvalidOperationException) // Handle not created
{
return false;
}
return true;
}
// --- Private Static Methods ---
private static void InitStaticFields()
{
_methodInvokeDelegate = new InvokeDelegateDelegate(InvokeDelegate);
_methodInvokeMethod = new InvokeMethodDelegate(InvokeMethod);
}
private static object InvokeDelegate(Control control, Delegate method, object[] args)
{
if (!control.IsHandleCreated || control.IsDisposed)
return null;
return method.DynamicInvoke(args);
}
private static void InvokeMethod(Control control, MethodInvoker method)
{
if (!control.IsHandleCreated || control.IsDisposed)
return;
method();
}
// --- Private Nested Types ---
delegate object InvokeDelegateDelegate(Control control, Delegate method, object[] args);
delegate void InvokeMethodDelegate(Control control, MethodInvoker method);
}
Cela peut au moins l'atténuer. Mon code tel qu'il est écrit ne nécessite pas Invoke? Ces exceptions sont lancées environ 1 fois sur 10. Je peux les tester! :) – drifter
Ce n'est pas le cas, pas besoin de retarder le thread et attendre que le délégué a fini de fonctionner. Vous ne faites rien * après * l'appel Invoke. Vous ne pouvez pas vraiment le tester une fois que vous utilisez BeginInvoke, vous devez ouvrir et fermer votre formulaire au moins un million de fois. Soyez assuré que la course est toujours là, vous aurez besoin d'attraper ODE. –
Cela ne me dérangerait pas d'attraper ObjectDisposedException, mais parfois il lance InvalidOperationException à la place ("Invoke ou BeginInvoke ne peut pas être appelé sur un contrôle tant que le handle de fenêtre n'a pas été créé.") Je ne peux pas l'attraper InvalidOperationException est dans le code invoqué, n'est-ce pas? – drifter