Question

J'ai un PropertyGrid dans mon application qui permet d'éditer des objets arbitraires. Je dois être en mesure d'exécuter un sous-programme arbitraire sur un autre thread qui se penche également sur ces objets (fonctionnalité de recherche, si vous êtes curieux). La question évidente est qu'un utilisateur pourrait être d'éditer un de ces objets en même temps mon fil de recherche est la lecture, ce qui serait préférable d'éviter (bien qu'il ne sera probablement pas un résultat autre critique depuis mon fil de recherche est simplement en train de lire, ne pas écrire).

L'appel lock(obj) est assez facile de mon fil de recherche, mais après avoir regardé à travers la documentation et un bref Survoler le code PropertyDescriptorGridEntry dans le réflecteur, je ne peux pas l'air de trouver un endroit analogue à utiliser un appel System.Threading.Monitor.Enter()/Exit() sur l'objet en question sur la PropertyGrid. J'espérais qu'il y aurait BeginEdit et les événements EndEdit ce qui en ferait assez simple, mais je ne peux pas sembler trouver une telle chose. Je préfère ne pas verrouiller l'ensemble de l'objet alors qu'il est exposé dans le PropertyGrid comme cela bloquer évidemment mon fil de recherche jusqu'à ce qu'un autre objet a été sélectionné.

Je suis un peu nouveau pour le modèle de thread de Windows Forms, donc j'espère qu'il ya une réponse évidente que je viens de négliger. Toute aide?

Modifier clonage Synchrone mes objets avant de lancer la recherche de manière asynchrone sera probablement assez inefficace que je pourrais aussi bien lancer la recherche elle-même de manière synchrone - le point d'exécuter de manière asynchrone est bien sûr de permettre à mes utilisateurs de continuer à travailler pendant la recherche est en cours d'exécution. La recherche a besoin à l'échelle bien, comme l'ensemble des données que je traversais finira finalement par être arbitrairement grand, ce qui rend le clonage synchrone ressembler à cela causera le problème de la facilité d'utilisation, je suis en train d'éviter.

Était-ce utile?

La solution

Je pense que vous allez devoir faire un peu de travail pour cela.

Tout d'abord, vous devez créer une implémentation de ICustomTypeDescriptor qui fonderait sa mise en œuvre sur tout ce TypeDescriptor vous obtiendriez normalement pour ce type.

Ensuite, dans les mises en œuvre des méthodes qui exposent les descripteurs des membres que vous souhaitez verrouiller, vous fournir des sous-classes qui dérivent de ces descripteurs et remplacer les méthodes appropriées pour envelopper un verrou autour.

Donc, pour une propriété, vous implémenteriez GetProperties pour retourner vos sous-classes spécifiques de PropertyDescriptor. Ces sous-classes primeraient les méthodes GetValue et SetValue (et d'autres) et utiliser un verrou lors de l'accès aux variables.

Il convient de mentionner que le verrouillage comme celui-ci dans le thread d'interface utilisateur est probablement une mauvaise idée, puisque vous ne voulez pas bloquer arbitrairement les opérations sur ce thread. Il pourrait être préférable de simplement créer un clone de l'objet et une méthode qui met à jour le magasin d'objets lorsque vous avez terminé.

Autres conseils

Ce sera en effet pas thread-safe. Vous pouvez maréchal bits du code de recherche sur le thread d'interface utilisateur, mais qui va ralentir les choses, et peut-être vaincre le point du filetage ...

Comment la recherche rapide besoin d'être? Pouvez-vous travailler contre un clone? etc

Pouvez-vous cloner les données avant de l'afficher, et obtenez votre fil de recherche pour travailler sur le clone? Si vous voulez que le fil de recherche pour « voir » les changements, vous pouvez répondre à des événements sur le PropertyGrid et peut-être faire contrôle modifications au clone en quelque sorte. (Il est probablement plus facile d'utiliser simplement les données « obsolètes », bien.)

Je sais que les données de clonage semble affreusement inefficace, mais le filetage certainement plus simple quand chaque fil fonctionne sur des données complètement indépendantes (ou tous les fils en lecture seule).

Je peux me tromper, mais il me semble que vous venez de la mauvaise fin.

Il y a deux questions distinctes, vous devez répondre.

Tout d'abord, faire en sorte que le PropertyGrid est que jamais accessible sur le thread d'interface utilisateur. Si l'une de ses méthodes (y compris getter de la propriété / setters) sont accessibles à partir d'autres threads, vous souffrez la douleur de façon mystérieuse. Les exceptions sont InvokeRequired() et Invoke, bien sûr.

En second lieu, vous assurer que votre fil de recherche peut fonctionner correctement.

Pour résoudre le premier problème, soit assurez-vous ne sont jamais modifiés vos objets sauf par le thread d'interface utilisateur, ou faire tout votre événement déclencheurs du fil au courant afin que vos événements d'objets (tels que PropertyChanged) ne sont jamais déclenché sur le thread d'interface utilisateur.

Le deuxième problème est plus facile - aussi longtemps que votre fil de recherche ne fait que lire vos objets de base, tout devrait bien fonctionner. Oui, votre fil de recherche peut voir par inadvertance des données partiellement mises à jour, mais est-ce vraiment un problème?

Quelques réflexions finales ...

  • Ne pas mettre en œuvre votre recherche à itérer PropertyGrid lui-même; obtenir une liste des objets à l'avant (ils ne doivent pas nécessairement être des clones) et de travailler à travers ce lieu.

  • Avez-vous envisagé d'utiliser Idle traitement pour faire la recherche? L'objet Application déclenche un événement à chaque fois que l'application est à court de messages à traiter - vous pouvez accrocher dans ce et effectuer une étape de votre recherche chaque fois que l'événement est déclenché. Une sorte de filetage pauvre-mans, mais avec aucun des maux de tête mutex / lock / sémaphone. Je l'ai utilisé pour ce très bon effet dans le passé.

Mise à jour : Si je me souviens bien, PropertyGrid respecte le IEditableObject interface , appelant BeginEdit dès que vous commencez à modifier une ligne, et

scroll top