Question

Je rencontre un problème avec une application Windows Forms.

Un formulaire doit être affiché à partir d'un autre thread. Ainsi, dans la classe de formulaire, je le code suivant:

private delegate void DisplayDialogCallback();

public void DisplayDialog()
{
    if (this.InvokeRequired)
    {
        this.Invoke(new DisplayDialogCallback(DisplayDialog));
    }
    else
    {
        this.ShowDialog();
    }
}

Maintenant, chaque fois que je lance cela, un InvalidOperationException est jeté sur la ligne this.ShowDialog();:

"opération de la Croix-fil non valide. Control 'SampleForm' accessible à partir d'un autre thread que le thread il a été créé"

Le mal de Qu'est-ce avec ce morceau de code? Est-il pas un moyen valable de faire des appels inter-fil? Y at-il quelque chose de spécial avec ShowDialog()?

Était-ce utile?

La solution

Essayez celui-ci:

private delegate void DisplayDialogCallback();

public void DisplayDialog()
{
    if (this.InvokeRequired)
    {
        this.Invoke(new DisplayDialogCallback(DisplayDialog));
    }
    else
    {
        if (this.Handle != (IntPtr)0) // you can also use: this.IsHandleCreated
        {
            this.ShowDialog();

            if (this.CanFocus)
            {
                this.Focus();
            }
        }
        else
        {
            // Handle the error
        }
    }
}

S'il vous plaît noter que le rendement des InvokeRequired

  

true si la poignée du contrôle était   créé sur un fil différent de celui du   thread appelant (indiquant que vous   doit faire des appels au contrôle par   une méthode d'appel); sinon, false.

et, par conséquent, si le contrôle n'a pas été créée, la valeur de retour sera false!

Autres conseils

Vous êtes en train d'exécuter ce code probablement avant que le formulaire a été démontré.
Par conséquent, InvokeRequired revient false.

Je crois que ce qui se passe ici est que ce code est en cours d'exécution avant que le Form est jamais montré.

Quand un Form est créé en .Net il ne gagne pas immédiatement une affinité pour un fil particulier. Que lorsque certaines opérations sont effectuées comme montrant ou saisir la poignée-t-il une affinité gain. Avant cela arrive, il est difficile pour InvokeRequired de fonctionner correctement.

Dans ce cas particulier aucune affinité est établie et aucun contrôle parent existe donc retourne InvokeRequired faux car il ne peut pas déterminer le fil d'origine.

La façon de résoudre ce problème est d'établir une affinité pour votre contrôle quand il est créé sur le thread d'interface utilisateur. La meilleure façon de le faire est juste de demander le contrôle de sa propriété de poignée.

var notUsed = control.Handle;

vous obtenez probablement ce code avant que le formulaire a été montré et donc la poignée de fenêtre n'a pas été créée.

Vous pouvez ajouter ce code avant votre code et tout devrait être bon:

if (! this.IsHandleCreated)
   this.CreateHandle();

Modifier Il y a un autre problème avec votre code. Une fois que le formulaire est affiché, vous ne pouvez pas appeler ShowDialog () à nouveau. Vous obtiendrez une exception d'opération non valide. Vous pouvez modifier cette méthode comme d'autres l'ont proposé.

Vous pourriez être mieux servi d'appeler le ShowDialog () directement à partir de la classe d'appel et une autre méthode pour BringToFront () ou quelque chose comme ça ...

Vous pouvez toujours essayer de tester contre un autre contrôle.

Par exemple, vous pouvez accéder à des collections de Application.Forms

public Control GetControlToInvokeAgainst()
{
    if(Application.Forms.Count > 0)
    {
        return Application.Forms[0];
    }
    return null;
}

Ensuite, dans votre méthode DisplayDialog (), appelez le GetControlToInvokeAgainst () et test nul avant d'essayer d'effectuer un appel InvokeRequired.

Très probablement la poignée du contrôle est pas encore créé, dans lequel le rendement de cas Control.InvokeRequired false.

Vérifiez la propriété Control.IsHandleCreated pour voir si tel est le cas.

Je pense aussi SLaks est correct. De msdn ( http://msdn.microsoft .com / fr-fr / bibliothèque / system.windows.forms.control.invokerequired.aspx ):

  

Si aucune poignée appropriée peut être trouvée, la méthode renvoie InvokeRequired faux.

S'il est possible dans votre cas, je voudrais essayer de combiner la création et montrant le contrôle dans une seule méthode, i.e.:.

public DisplayDialog static Show()
{
  var result = new DisplayDialog; //possibly cache instance of the dialog if needed, but this could be tricky
  result.ShowDialog(); 
  return result;
}

vous pouvez appeler Afficher à partir d'un autre thread

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top