2013-03-16 3 views
3

Je suis nouveau en C#. J'ai deux button et deux label. Ce que je veux, c'est que, lorsque je clique sur button1commence en comptant et montre en label1. Lorsque j'appuie sur button2, il reprend le comptage sous button1 et commence en comptant sous button2 et s'affiche dans label2. Voici mon codeActiver ou désactiver le bouton en fonction d'un autre bouton

bool testt = true; 
int i = 0; 
int j = 0; 

private void button1_Click(object sender, EventArgs e) 
{ 
    while (testt) 
    { 
     label1.Text = i.ToString(); 
     i++; 
     System.Threading.Thread.Sleep(50); 
     if (i > 5000) 
     { 
      i = 0; 
     } 
    } 
} 

private void button2_Click(object sender, EventArgs e) 
{ 
    testt = false; 
    while (!testt) 
    { 
     label2.Text = j.ToString(); 
     j++; 
     System.Threading.Thread.Sleep(50); 
     if (j > 5000) 
     { 
      i = 0; 
     } 
    } 
} 

Ici, le problème est lorsque je clique sur un bouton, il ne me permet pas de cliquer sur un autre bouton. J'ai utilisé une variable globale pour détecter quel bouton a été enfoncé. Mais ça ne marche pas. Comment puis-je faire ce travail?

+0

juste suivez ce [truc] (http://lostechies.com/gabrielschenker/2009/01/23/synchronizing-calls-to-the-ui-in-a-multi-threaded-application/) – spajce

Répondre

2

Vous faites tout cela sur le thread d'interface utilisateur, de sorte que vous bloque. Vous devez disposer d'un autre thread pour effectuer le comptage et déléguer le changement d'étiquette au thread principal en utilisant Control.Invoke afin que le thread principal ait le temps d'exécuter la pompe de message. Vous pouvez utiliser le BackgroundWorker intégré ou créer simplement un fil avec ThreadPool ou TaskFactory.

J'ai écrit un court exemple de la façon dont cela peut être accompli avec LINQ et ThreadPool, ce n'est pas le plus sage conception d'approche, mais il vous donnera un point de départ sur le développement d'une solution adéquate

semaphore = true; 
    int i = 0; 
    int j = 0; 

    private void button1_Click(object sender, EventArgs e) 
    { 
     semaphore = true; 
     ExecuteAsync(()=> 
      { 
       while (semaphore) 
       { 
        //Dispatch a call to the UI thread to change the label 
        Invoke((MethodInvoker)(() => ChangeLabel(label1, i.ToString()))); 
        i++; 
        Thread.Sleep(50); 
        if (i > 5000) 
        { 
         i = 0; 
        } 
       } 
      }); 
    } 

    //Executes a function on a ThreadPool thread 
    private void ExecuteAsync(Action action) 
    { 
     ThreadPool.QueueUserWorkItem(
      obj => action()); 
    } 

    private void ChangeLabel(Label label, string labelText) 
    { 
     label.Text = labelText; 
    } 

    private void button2_Click(object sender, EventArgs e) 
    { 
     semaphore = false; 
     ExecuteAsync(() => 
       { 
        while (!semaphore) 
        { 
         //Dispatch a call to the UI thread to change the label 
         Invoke((MethodInvoker)(() => ChangeLabel(label2, j.ToString()))); 
         j++; 
         Thread.Sleep(50); 
         if (j > 5000) 
         { 
          i = 0; 
         } 
        } 
       }); 
    } 
+0

J'ai essayé d'utiliser BackgroundWorker. Dans ce cas, cliquez sur le bouton mais je ne peux toujours pas cliquer sur un autre bouton – asdfkjasdfjk

+0

quand je clique sur le bouton1 cela fonctionne et quand je clique sur le bouton2 il reprend le compte1 et commence à compter sous le bouton2 mais quand je clique sur le bouton1 ça ne marche plus étiqueter deux continuer à compter. Quoi qu'il en soit, merci pour la solution – asdfkjasdfjk

+0

J'ai édité ma réponse pour faire fonctionner les boutons alternativement. – mematei

0

Le problème que vous avez ici est un problème de thread. Lorsque vous avez des winforms, le thread principal a pour tâche d'afficher et de rendre l'interface interactive ET d'effectuer toutes les tâches que vous lui confiez.

Dans votre code, vous démarrez le compte à rebours. Mais là, le même thread qui fait fonctionner l'interface est maintenant occupé à diminuer votre valeur, donc il ne mettra pas à jour l'interface ou ne répondra pas aux boutons jusqu'à ce qu'il soit prêt.

Ce que vous voulez, c'est un thread d'assistance pour faire le compte à rebours pour vous (ou, honnêtement, démarrer un TIMER à la place). Sinon, l'interface sera non interactive jusqu'à ce que vous ayez terminé cette boucle.

La minuterie est le moyen le plus simple de le faire.

http://msdn.microsoft.com/en-us/library/system.windows.forms.timer.aspx

+0

en fait ce résumé d'un autre problème. Je viens de donner le concept ici. J'ai besoin de savoir comment cela peut être fait sans minuterie. – asdfkjasdfjk

+0

Dans ce cas, vous devrez générer un nouveau thread quelque chose comme la classe BackgroundWorker. Le problème est alors que vous aurez besoin de déléguer les tâches de clic - puisque l'interface utilisateur ne peut être fait sur le thread principal. Le correctif rapide, facile et TRÈS sale consiste à exécuter Application.DoEvents() dans la boucle. – Haedrian

+0

Cela pourrait aider: http://stackoverflow.com/questions/661561/how-to-update-the-gui-from-another-thread-in-c – Haedrian

Questions connexes