Suite

Exécution de la méthode async dans la commande relay à l'aide d'ArcGIS Pro SDK et MVVM ?


Je développe un dockpane "outil de recherche" dans le SDK ArcGIS Pro à l'aide de MVVM. J'ai un bouton sur mon Dockpane connecté à une commande de relais dans mon modèle de vue, qui essaie d'appeler une méthode asynchrone dans mon maquette pour retourner une liste de résultats :

///  /// Résultats de recherche ///  Collection Observable privée _searchResults = new ObservableCollection(); liste IL publique SearchResults { get { return _searchResults; } } ///  /// Commande du bouton de recherche ///  ICommand privé _searchCommand; public ICommand SearchCommand { get { _searchCommand = new RelayCommand( async() => { SearchResults.Clear(); var results = wait DockFindModel.SearchAsync(_selectedSearchableLayer, _searchString); foreach (var élément dans les résultats) { SearchResults.Add(item) ; } //notifier les résultats ont changé NotifyPropertyChanged(() => SearchResults); }, () => bAppRunning); // la commande ne s'exécutera que si l'application est en cours d'exécution return _searchCommand; } }

Cependant, j'obtiens l'exception suivante lorsque la commande relay essaie de s'exécuter :

Une exception non gérée de type 'System.AggregateException' s'est produite dans mscorlib.dll

Informations supplémentaires : les exceptions d'une tâche n'ont pas été observées en attendant la tâche ou en accédant à sa propriété Exception. Par conséquent, l'exception non observée a été renvoyée par le thread du finaliseur.

J'ai essayé un certain nombre de choses dans ce fil pour essayer de résoudre le problème sans succès. Je suis sûr que l'exécution de méthodes aync dans une commande relay est assez fondamentale pour le SDK ArcGIS Pro, car ESRI vous recommande d'utiliser MVVM, et de nombreuses méthodes fournies doivent être exécutées de manière asynchrone.

Quelqu'un a-t-il de la chance avec ça?


La classe QueuedTask est utilisée à la place de la classe Task pour les raisons suivantes :

Contrôle des files d'attente et de la concurrence

Lorsque les tâches sont distribuées à l'aide de Task.Run, la tâche associée s'exécutera sur un thread aléatoire dans le pool de threads géré à chaque fois qu'elle est appelée. Si un appel ultérieur à Task.Run est appelé à partir de n'importe où dans l'application, la nouvelle tâche commencera à s'exécuter immédiatement sur un autre thread potentiellement alors que la première tâche est toujours en cours d'exécution sur le premier thread. Pour en revenir à la liste des défis inhérents au code multithread, il devrait être évident que l'exécution simultanée d'opérations non organisées est susceptible d'entraîner des plantages et une corruption de l'état de l'application. Le comportement de mise en file d'attente de QueuedTask.Run garantit le bon ordre des appels et réduit le risque de conflits. N'oubliez pas que le parallélisme en cours dans ArcGIS Pro est réalisé en interne ; cela simplifie le modèle de programmation publique et réduit considérablement la probabilité de conflits.

Affinité et état

Pour des raisons de performances, ArcGIS Pro conserve un état considérable sur des threads spécifiques et, dans de nombreux cas, utilise des objets qui ont une affinité de thread. L'affinité de thread signifie qu'un objet est lié à un thread particulier et ne doit pas être interagi avec un thread à l'exception du thread avec lequel il a une affinité. Les contraintes d'affinité sont courantes dans les systèmes d'exploitation et les composants, notamment les connexions aux bases de données, les fenêtres, les contrôles, les files d'attente d'entrée, les minuteurs, les bitmaps WPF et les serveurs COM. Dans WPF par exemple, l'appel de méthodes sur n'importe quel objet dérivé de la classe WPF DependencyObject entraînera une exception si l'appel est effectué à partir d'un thread sur lequel l'objet n'a pas été créé.

Les threads du pool de threads managés sont également incompatibles avec la plupart des composants COM, vous ne devez donc pas essayer d'utiliser Task.Run avec du code susceptible d'exécuter des composants COM directement ou indirectement.

Intégration d'applications

Lorsque les tâches sont distribuées à l'aide de QuededTask.Run, elles sont automatiquement intégrées aux diverses fonctionnalités de l'application comme suit :

• Le cadre de progression/annulation étendu où la progression, y compris la boîte de dialogue de progression programmable, est affichée et masquée automatiquement et où l'état d'annulation est correctement communiqué entre les parties pertinentes de l'application.

• Le système d'état d'occupation de l'application où les éléments de l'interface utilisateur tels que les boutons et les outils sont automatiquement activés et désactivés lorsque les tâches sont en cours d'exécution. L'exécution des tâches peut également être coordonnée avec des phases critiques telles que la création de vues et l'arrêt d'applications.

• Les tâches en file d'attente sont inscrites dans les fonctions de diagnostic du framework, lorsqu'elles sont activées. Cela permet aux développeurs de surveiller la séquence d'exécution des tâches, les fonctions exécutées par les tâches et la durée d'exécution. Ce type d'informations est inestimable pour le débogage et l'analyse des performances.

Cas acceptables pour l'utilisation de Task.Run

Il existe des cas où l'utilisation de Task.Run est acceptable, comme lors de l'exécution d'opérations en arrière-plan indépendantes composées entièrement de code managé, tant que les composants managés particuliers utilisés n'ont pas d'affinité de thread. Le développeur assume l'entière responsabilité de la gestion de l'annulation, de l'affichage de la progression, de l'activation/désactivation appropriée de l'interface utilisateur, de la coordination des opérations et de la gestion des conflits logiques.


Ok, j'ai donc réussi à résoudre le problème en modifiant la façon dont j'exécute ma méthode asynchrone.

J'ai changé ça :

var result = wait DockFindModel.Search();

Pour ça:

var result = wait QueuedTask.Run(() => DockFindModel.Search());

Bien que je sois un peu confus quant à la raison pour laquelle je dois attendre Task.Run() lorsque relaycommand accepte déjà async lambda. Je suis sûr que cela deviendra clair avec le temps cependant.


La concurrence est l'un des problèmes à résoudre lors de l'exécution de code en parallèle. La synchronisation peut être un simple lock() sur un objet (mais pas ce) et il y a de bonnes raisons de mettre l'exécution en file d'attente, mais la simultanéité et les plantages n'en font pas partie. La file d'attente est toujours séquentielle, donc pour une exécution parallèle, vous devez juste apprendre à la gérer au lieu de l'éviter.


Voir la vidéo: ArcGIS Pro SDK for.NET: UI Design and MVVM (Octobre 2021).