Question

Vous rencontrez des difficultés avec la syntaxe pour appeler un délégué de manière anonyme dans un Control.Invoke.

Nous avons essayé différentes approches sans succès.

Par exemple:

myControl.Invoke(delegate() { MyMethod(this, new MyEventArgs(someParameter)); }); 

où someParameter est local à cette méthode

Ceci entraînera une erreur de compilation:

  

Impossible de convertir une méthode anonyme en type 'System.Delegate' car ce n'est pas un type délégué

Était-ce utile?

La solution

Parce que Invoke / BeginInvoke accepte Delegate (plutôt qu'un délégué tapé), vous devez indiquer au compilateur le type de délégué à créer. ; MethodInvoker (2.0) ou Action (3.5) sont des choix courants (notez qu'ils ont la même signature); comme si:

control.Invoke((MethodInvoker) delegate {this.Text = "Hi";});

Si vous devez transmettre des paramètres, alors "variables capturées". sont le chemin:

string message = "Hi";
control.Invoke((MethodInvoker) delegate {this.Text = message;});

(mise en garde: vous devez être un peu prudent si vous utilisez des captures async , mais sync est correct - c'est-à-dire que ce qui est correct est correct)

Une autre option consiste à écrire une méthode d'extension:

public static void Invoke(this Control control, Action action)
{
    control.Invoke((Delegate)action);
}

alors:

this.Invoke(delegate { this.Text = "hi"; });
// or since we are using C# 3.0
this.Invoke(() => { this.Text = "hi"; });

Vous pouvez bien sûr faire de même avec BeginInvoke :

public static void BeginInvoke(this Control control, Action action)
{
    control.BeginInvoke((Delegate)action);
}

Si vous ne pouvez pas utiliser C # 3.0, vous pouvez faire la même chose avec une méthode d'instance régulière, probablement dans une classe de base Form .

Autres conseils

En fait, vous n'avez pas besoin d'utiliser le mot clé délégué. Il suffit de passer lambda en tant que paramètre:

control.Invoke((MethodInvoker)(() => {this.Text = "Hi"; }));
myControl.Invoke(new MethodInvoker(delegate() {...}))

Vous devez créer un type de délégué. Le mot clé 'delegate' dans la création de la méthode anonyme est un peu trompeur. Vous ne créez pas un délégué anonyme, mais une méthode anonyme. La méthode que vous avez créée peut être utilisée dans un délégué. Comme ceci:

myControl.Invoke(new MethodInvoker(delegate() { (MyMethod(this, new MyEventArgs(someParameter)); }));

Par souci d’exhaustivité, ceci peut également être réalisé via une combinaison méthode Action / méthode anonyme:

//Process is a method, invoked as a method group
Dispatcher.Current.BeginInvoke((Action) Process);
//or use an anonymous method
Dispatcher.Current.BeginInvoke((Action)delegate => {
  SomeFunc();
  SomeOtherFunc();
});

J'ai eu des problèmes avec les autres suggestions car je veux parfois renvoyer des valeurs de mes méthodes. Si vous essayez d'utiliser MethodInvoker avec des valeurs de retour, cela ne semble pas vous plaire. La solution que j’utilise est donc la suivante (très heureux d’entendre un moyen de rendre cela plus succinct - j’utilise c # .net 2.0):

    // Create delegates for the different return types needed.
    private delegate void VoidDelegate();
    private delegate Boolean ReturnBooleanDelegate();
    private delegate Hashtable ReturnHashtableDelegate();

    // Now use the delegates and the delegate() keyword to create 
    // an anonymous method as required

    // Here a case where there's no value returned:
    public void SetTitle(string title)
    {
        myWindow.Invoke(new VoidDelegate(delegate()
        {
            myWindow.Text = title;
        }));
    }

    // Here's an example of a value being returned
    public Hashtable CurrentlyLoadedDocs()
    {
        return (Hashtable)myWindow.Invoke(new ReturnHashtableDelegate(delegate()
        {
            return myWindow.CurrentlyLoadedDocs;
        }));
    }

Je n'ai jamais compris pourquoi cela fait une différence pour le compilateur, mais cela suffit.

public static class ControlExtensions
{
    public static void Invoke(this Control control, Action action)
    {
        control.Invoke(action);
    }
}

Bonus: ajoute un traitement d'erreur, car si vous utilisez Control.Invoke à partir d'un thread d'arrière-plan, vous mettez à jour l'état text / progress / enabled d'un contrôle et vous ne le faites pas. ne vous inquiétez pas si le contrôle est déjà éliminé.

public static class ControlExtensions
{
    public static void Invoke(this Control control, Action action)
    {
        try
        {
            if (!control.IsDisposed) control.Invoke(action);
        }
        catch (ObjectDisposedException) { }
    }
}
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top