Question

J'écris une application WinForms qui a deux modes: console ou interface graphique. Trois projets dans la même solution, un pour l'application console, un pour les formulaires d'interface utilisateur et le troisième pour détenir la logique selon laquelle les deux interfaces se connecteront également. L'application Console fonctionne parfaitement.

Un modèle qui contient les sélections de l'utilisateur, il a un IList<T> où T est un objet local, Step, qui implémente INotifyPropertyChanged, de sorte que dans l'interface utilisateur, il est monté sur un DataGridView. Tout va bien à l'exécution, l'état initial des objets est reflété à l'écran.

Chacun des StepResult objets est une tâche qui est exécutée à son tour. certaines propriétés vont changer, elles seront reflétées dans IList et transmises à DataGridView.

Cette action dans les versions de l'interface utilisateur est réalisée en créant un BackgroundWorker relançant des événements vers l'interface utilisateur. Le r le fait et génère un objet <=> qui est un type énuméré indiquant un résultat (par exemple, Running, NotRun, OK, NotOK, Caveat) et une chaîne pour indiquer un message (car l'étape a été exécutée mais pas attendu, c'est-à-dire avec une mise en garde). Normalement, les actions impliqueront une interaction avec la base de données, mais en mode débogage, je génère un résultat de manière aléatoire.

Si le message est null, il n'y a jamais de problème, mais si je génère une réponse comme celle-ci:

StepResult returnvalue = new StepResult(stat, "completed with caveat")

Un message d'erreur me dit que l'accès à DataGridView a été effectué à partir d'un thread autre que celui sur lequel il a été créé. (Je suis en train de passer cela à travers un gestionnaire personnalisé qui devrait gérer l'invocation si nécessaire - peut-être que non?)

Ensuite, si je génère une réponse unique, par ex. en utilisant un nombre aléatoire <=>:

StepResult returnvalue = new StepResult(stat, r.ToString());

les actions réussissent sans problème, les nombres sont écrits proprement dans le DataGridView.

Je suis dérouté. Je suppose que c'est en quelque sorte un problème de chaîne littérale, mais quelqu'un peut-il proposer une explication plus claire?

Était-ce utile?

La solution

Puisque vous établissez une liaison avec l'interface utilisateur via l'abonnement aux événements, cela pourrait vous être utile ; C’est un exemple que j’ai écrit il ya quelque temps et qui montre comment sous-classer BindingList<T> afin que les notifications soient automatiquement regroupées dans le fil de l'interface utilisateur.

S'il n'y a pas de contexte de synchronisation (c'est-à-dire en mode console), il revient alors à l'appel direct simple, il n'y a donc pas de surcharge. Lors de l'exécution dans le thread d'interface utilisateur, notez que ceci utilise essentiellement Control.Invoke, qui lui-même exécute le délégué directement s'il se trouve sur le thread d'interface utilisateur. Donc, il n’existe que des commutateurs si les données sont en cours d’édition à partir d’un thread non-UI - indique ce que nous voulons ;-p

Autres conseils

Vous avez répondu à votre propre question: -

  

Je reçois une erreur indiquant que DataGridView était en cours d'accès via un thread autre que celui sur lequel il avait été créé.

WinForms insiste sur le fait que toutes les actions effectuées sur les formulaires et les contrôles sont effectuées dans le contexte du thread dans lequel le formulaire a été créé. La raison en est complexe, mais elle a beaucoup à voir avec l'API Win32 sous-jacente. Pour plus de détails, consultez les différentes entrées du blog The Old New Thing .

Vous devez utiliser les méthodes InvokeRequired et Invoke pour vous assurer que les contrôles sont toujours accessibles à partir du même thread (pseudocodeish):

object Form.SomeFunction (args)
{
  if (InvokeRequired)
  {
    return Invoke (new delegate (Form.Somefunction), args);
  }
  else
  {
    return result_of_some_action;
  }
}

J'ai eu ce même problème avant. Peut-être que cet article que j'ai posté à ce sujet peut aider.

http: //cyberkruz.vox .com / bibliothèque / post / net-problème-async-et-windows-forms.html

J'ai trouvé cet article - & "; Mise à jour de IBindingList à partir d'un thread différent " - qui a accusé BindingList du doigt -

  

Etant donné que la BindingList n'est pas configurée pour des opérations asynchrones, vous devez mettre à jour la BindingList à partir du même thread sur lequel elle était contrôlée.

Transférer explicitement le formulaire parent en tant qu'objet ISynchronizeInvoke et créer un wrapper pour le BindingList<T> a fonctionné.

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