2009-11-11 5 views
0

J'ai un Windows Forms (C#) projet avec plusieurs comboboxes/listboxes etc qui sont remplis lors du chargement du formulaire. Le problème est que le chargement des comboboxes/listboxes est lent, et puisque le chargement est effectué lorsque le formulaire tente d'afficher le formulaire entier n'est pas affiché jusqu'à ce que tous les contrôles ont été remplis. Cela peut dans certaines circonstances être 20 + secondes. S'il y avait un type d'événement Form_finished_loaded, j'aurais pu y mettre mon code, mais je ne peux pas trouver un événement qui se déclenche une fois que le formulaire a fini de dessiner les contrôles de base.chargement Délai de combobox lorsque le formulaire charges

j'ai une exigence bien - le chargement doit être fait dans le thread principal (puisque je reçois les éléments d'un COM-application conviviale non-threading).

J'ai trouvé une solution possible, mais peut-être il y a une meilleure façon? Je peux créer un System.Timer.Timer lors de la création du formulaire et faire en sorte que le premier tick soit appelé environ 1 seconde plus tard, puis remplir les listes à partir de ce tick. Cela donne suffisamment de temps à la forme pour être affichée avant qu'elle ne commence à remplir les listes.

Quelqu'un at-il d'autres conseils sur la façon de retarder le chargement des contrôles?

Répondre

6

Il est le Shown event que « se produit chaque fois que le formulaire est affiché. ». Aussi, vous pouvez utiliser les fonctions BeginUpdate and EndUpdate pour accélérer le remplissage de votre combobox.

+1

+1 pour le conseil BeginUpdate/EndUpdate. –

+0

BeginUpdate et EndUpdate ne sont-ils pas utilisés pour suspendre la peinture tout en chargeant un grand nombre d'éléments de façon séquentielle dans le contrôle et non quelque chose que vous utiliseriez pour un processus de longue durée? +1 pour l'événement affiché. –

+0

Ça a marché! Le BeginUpdate/EndUpdate a fait une différence spectaculaire lors de l'ajout d'énormes collections. Jusqu'à 10 fois plus d'amélioration –

0

Pouvez-vous obtenir vos données d'un service Web qui appelle le composant COM? De cette façon, vous pouvez afficher des contrôles vides sur un formulaire verrouillé au début, effectuer des appels asynchrones pour obtenir les données et, en retour, remplir les combos respectifs, et une fois que tous sont chargés, vous pouvez déverrouiller le formulaire pour l'utilisateur à utiliser.

0

Vous pouvez écouter l'événement VisibleChanged et la première fois sa valeur est vrai que vous mettez votre code d'initialisation.

1

Il a cette certaine odeur de solution, mais cette approche devrait répondre à vos besoins:

private bool _hasInitialized = false; 
private void Form1_Shown(object sender, EventArgs e) 
{  
    if (!_hasInitialized) 
    { 
     ThreadPool.QueueUserWorkItem(state => 
     { 
      Thread.Sleep(200); // brief sleep to allow the main thread 
           // to paint the form nicely 
      this.Invoke((Action)delegate { LoadData(); });  
     }); 
    } 
} 

private void LoadData() 
{ 
    // do the data loading 
    _hasInitialized = true; 
} 

Ce qu'il fait est qu'il réagit lorsque le formulaire est affiché, vérifie si elle a déjà été initialisé avant, et sinon, il génère un thread qui attendra un court instant avant d'appeler la méthode LoadData sur le thread principal. Cela permettra au formulaire d'être peint correctement. Le quelque chose pourrait peut-être être atteint en appelant simplement this.Refresh() mais j'aime l'idée de laisser le système décider comment faire le travail.

je toujours essayer de pousser le chargement de données sur un thread de travail, en invoquant de nouveau sur le thread principal pour renseigner l'interface utilisateur (si elle est la mesure du possible avec le composant COM).

0

Est-ce que FormShown n'est pas l'événement que vous recherchez?

+0

Mais le thread de l'interface utilisateur bloquait toujours pendant que les contrôles se chargeaient, ce qui empêchait l'application de répondre, n'est-ce pas? –

+0

Allait éditer mon poste pour plus de détails:) ... Oui, et voici ce que Fredrik a suggéré (filetage). Je voudrais juste remplacer le Thread.Sleep() avec Application.DoEvents() avant de démarrer le thread. –

0

Lorsque vous dites que vous ne pouvez pas utiliser un fil d'arrière-plan à cause de COM, que voulez-vous dire? J'utilise de nombreux composants COM dans mes applications et les exécute sur des threads d'arrière-plan.

Si vous créez un nouveau thread comme STAThread vous pouvez probablement charger le ComboBox/ListBox sur un thread non-UI. IIRC ThreadPool alloue les threads de travail en tant que MTAThread. Vous devez donc créer un thread manuellement au lieu d'utiliser ThreadPool.QueueUserWorkItem.

Questions connexes