2010-10-07 4 views
3

J'ai une situation dans laquelle je veux extraire des données d'une base de données et l'affecter aux info-bulles de chaque ligne dans un contrôle ListView dans WPF. (J'utilise C# 4.0.) Comme je n'ai jamais fait ce genre de chose auparavant, j'ai commencé une application plus petite et plus simple pour obtenir les idées avant d'essayer de les utiliser dans mon application WPF principale.Quand l'exécution différée se produit-elle?

L'une de mes préoccupations est la quantité de données qui pourraient baisser. Pour cette raison, j'ai pensé que j'utiliserais LINQ to SQL, qui utilise l'exécution différée. Je pensais que cela aiderait et ne pas abattre les données jusqu'à ce que l'utilisateur passe leur souris sur la ligne pertinente. Pour ce faire, je vais utiliser une fonction distincte pour affecter les valeurs à l'info-bulle, à partir de la base de données, passées sur les paramètres que je dois passer aux procédures stockées pertinentes. Je fais 2 requêtes en utilisant LINQ to SQL, en utilisant 2 procédures stockées différentes, et en assignant les résultats à 2 DataGrids différents.

Même si je sais que LINQ to SQL utilise l'exécution différée, je commence à me demander si une partie du code que j'écris peut aller à l'encontre de mon intention d'utiliser LINQ to SQL. Par exemple, en testant dans mon application plus simple, je choisis plusieurs valeurs différentes pour voir comment cela fonctionne. Une sélection de valeurs n'a pas ramené de données, car il n'y avait pas de données pour les paramètres donnés. Je pensais que cela pourrait potentiellement causer la confusion de l'utilisateur, donc j'ai pensé que je vérifierais la propriété Count de la liste que j'assigne de l'exécution de la méthode associée DBML (liée à la procédure stockée). En y réfléchissant, je pense qu'il serait nécessaire pour LINQ d'exécuter la requête, afin de me donner un résultat pour la propriété Count. Est-ce que je ne suis pas correct?

Si j'élimine l'appel à la propriété Count de la liste, je me demande encore si je pourrais avoir un problème; si LINQ peut toujours être appelé, parce que j'associe l'info-bulle au contrôle via un appel de fonction?

Répondre

1

Vous devez utiliser Any(), pas Count(), mais même Any() provoquerez la requête à exécuter - après tout, il ne peut pas déterminer si oui ou non il y a des lignes dans le jeu de résultats sans exécuter la requête. Mais il y a l'exécution de la requête, et il y a récupération du jeu de résultats. Any() va chercher une ligne, Count() va les chercher tous.

Cela dit, je pense que d'avoir une opération non instantanée qui se produit sur mouseover est juste une mauvaise idée. Il y avait une version d'Outlook, une fois, qui affichait une info-bulle utile lorsque vous passiez la souris sur le bouton Imprimer. Moins utile, il a obtenu les données pour cette info-bulle en appelant la fonction système qui identifie les imprimantes disponibles.Donc, vous seriez en train d'atteindre un menu, et le bouton saisirait le pointeur de la souris et l'interface utilisateur se figer pendant deux secondes alors qu'il s'éteignait et compris comment afficher une info-bulle que vous ne demandiez même pas. Je déteste toujours ce programme aujourd'hui. Ne sois pas ce mec.

Une meilleure approche consisterait à obtenir vos données d'infobulle de manière asynchrone après le remplissage des données visibles sur l'écran. Il est assez facile de créer un BackgroundWorker qui récupère les données dans un DataTable, puis rend le DataTable disponible pour les modèles de vue dans le gestionnaire d'événements RunWorkerCompleted. (Faites-le ici pour ne pas mettre à jour les données liées à l'interface utilisateur sur le thread d'interface utilisateur.) Vous pouvez implémenter une propriété ToolTip dans votre modèle de vue qui renvoie une valeur par défaut (probablement null, mais peut-être quelque chose comme "Récupérer des données ... ") si le DataTable contenant des données d'info-bulle est nul, et cela calcule la valeur si ce n'est pas le cas. Cela devrait fonctionner admirablement. Vous pouvez même implémenter une notification de modification de propriété afin que l'info-bulle soit toujours mise à jour si l'utilisateur garde le pointeur de la souris dessus pendant que vous récupérez les données.

+0

Oh, je me souviens de cette version d'Outlook aussi, lorsque je passe la souris sur l'icône de l'imprimante dans la barre de menu. J'ai détesté ça! J'aime votre idée d'utiliser un processus de travail en arrière-plan pour récupérer les données sur un thread séparé. Je pense que je vais faire ça. – Rod

+0

C'est marrant, parce que c'est un problème d'interface utilisateur apparemment trivial, et pourtant c'est tellement ennuyeux que ça a complètement entaché l'expérience d'utiliser le programme pour moi. –

2

Vous avez raison, lorsque vous appelez la propriété Count il itère sur l'ensemble des résultats. Pas clair sur votre dernière question, mais le LINQ est probablement appelé au moment où vous remplissez vos DataGrids, bien après que l'info-bulle entre en jeu.

EDIT: Cependant, cela ne signifie pas qu'il y ait quelque chose de mal avec l'exécution deffered ou votre utilisation de celui-ci, il exécute à la dernière étape possible, lorsque vous avez besoin des données. Si vous voulez toujours vérifier le compte avant de récupérer toutes les données, vous pouvez avoir une simple fonction LINQ to SQL qui vérifie les lignes Any(). (En fait, tous() est probablement ce que vous voulez plus de Count> 0)

+0

Je ne connais pas Any() dans LINQ. Je vais devoir regarder dedans. Je vous remercie! – Rod

1

Alex est exact que l'appel Count() ou tout() énumérera l'expression LINQ provoquant la requête à exécuter. Je recommanderais de repenser votre conception car vous ne voulez probablement pas qu'une requête à la base de données soit exécutée chaque fois que l'utilisateur déplace sa souris. Il y a aussi le problème du délai pour interroger la base de données. Ce qui peut être instantané sur votre boîte de dev avec une base de données locale peut avoir un délai de plusieurs secondes sur un serveur fortement chargé. Je recommande de créer une fonction DisplayTooltip() qui prend une expression LINQ évaluée paresseusement. Vous pouvez ensuite mettre en cache les résultats ou appliquer d'autres heuristiques pour décider si vous devez réellement interroger la base de données ou non.

Questions connexes