2017-08-07 2 views
1

Ich mache einen Code in C#, wo ich einige Datensätze aus einer Access-Datenbank extrahieren, aber ich brauche die auf die nächste Iteration auf dem Klicken einer Schaltfläche abhängen . Ich habe versucht, mit einem Thread oder Aufgaben, aber es hat nicht funktioniert, weil es die Benutzeroberfläche blockiert, die ich es gesehen und klickbar benötigt.C# - Machen Sie UI-Funktion während einer Endlosschleife, bis die Taste gedrückt

Hier ist der Code:

bool nextClick = false ; 

       while (readerSelect.Read()) 
       { 

        // show the correct panel 
        if (string.Compare(readerSelect[2].ToString(), "P1") == 0) 
        { 
         // panel with type 1 
         textBoxP1Text1.Text = readerSelect[3].ToString(); 
         textBoxP1Text2.Text = readerSelect[4].ToString(); 
         pictureBoxP1Image.ImageLocation = readerSelect[6].ToString(); 

        } 
        else 
        { 
         // panel with type 2 
         textBoxP1Text2.Text = readerSelect[5].ToString(); 
        } 

    //this while need to be kind of infinite so the interation can't be processed and 
    //so when i need to change iteration i click the buttonNext 
        while (!nextClick) { 
        startWhile:; 
         MethodInvoker mi = delegate() { 
          if (nextClick) 
          { 
           Application.DoEvents(); 
           // System.Windows.Forms.Application.Run(); 
          } 

         }; 
         this.Invoke(mi); 
         //break; 
         goto startWhile; 
        } 

private void buttonNext_Click(object sender, EventArgs e) 
    { 
     // click on the next button 
     nextClick = true; 
    } 
+1

Wenn Sie nur nach einem Klick zum nächsten Element gehen müssen, dann verwenden Sie keine While-Schleife ... machen Sie einfach einen bei jedem Klick ... – Milney

+0

Dies wird einen großen Einfluss auf unsere Verbindung haben, die irgendwie ist arm, aber danke für die Antwort –

+0

Was meinst du eine "große Auswirkung auf Ihre Verbindung"? Das ist nur falsch. So wie du es jetzt machst und auf diese Weise wirst du immer nur lesen können, wie viele Aufzeichnungen es gibt. Du liegst falsch. Ich würde empfehlen, die DataReader-Dokumentation zu lesen, bis Sie sie als ersten Punkt besser verstehen. – Milney

Antwort

2

Während Dax Fohl Antwort funktioniert, scheint es, wie Sie ein Problem in Ihrem Design haben. Ich glaube, Sie verletzen die Single Responsibility Principle, indem Sie zu viel Geschäftslogik in der Form Klasse gehen.

Ich würde empfehlen, die Business-Logik in eine eigene Klasse zu zerlegen. Anstatt alles in einer Schleife durchlaufen zu lassen, verarbeiten Sie einfach das Ereignis click click des nächsten Datensatzes und zeigen das Ergebnis an. Hier ist ein Beispiel dafür, was ich meine:

public partial class Form1 : Form 
{ 
    private readonly DataProcessor dataProcessor = new DataProcessor(); 

    public Form1() 
    { 
     this.InitializeComponent(); 
    } 

    private void button1Next_Click(object sender, EventArgs e) 
    { 
     this.buttonNext.Enabled = false; 
     this.ProcessNext(); 
    } 

    private async void ProcessNext() 
    { 
     string s = await this.dataProcessor.ProcessNext(); 
     this.textBoxP1Text1.Text = s; 
     this.buttonNext.Enabled = true; 
    } 
} 

public class DataProcessor 
{ 
    private readonly Random r = new Random(); // Or reader or whatever. 

    public async Task<string> ProcessNext() // Just using `string` as an example. 
    { 
     await Task.Delay(1000); 
     return this.r.Next().ToString(); 
    } 
} 

Ich denke, das leichter zu verstehen und besser verwaltbar in der Zukunft. Wenn ein neues Teammitglied Semaphor-Kram (oder Ihr zukünftiges Selbst) betrachtet, wird es schwer zu verstehen sein/sich daran erinnern, was der Punkt von allem war. Hier haben Sie nur eine lokale Funktion, die eine Sache macht und einfach zu folgen ist.

3

Sie eine Semaphore in einem Asynchron-Aufgabe verwenden können, müssen Sie die Taste Release bei jedem Klick darauf und haben die while-Schleife erwarten sie durch jedes Mal. Hier ist ein kurzes Beispiel, eine Form verwenden, die ein button1 hat und ein label1 hinzugefügt, um es:

public partial class Form1 : Form 
{ 
    private readonly SemaphoreSlim signal = new SemaphoreSlim(0, int.MaxValue); 

    public Form1() 
    { 
     this.InitializeComponent(); 
     this.RunLoop(); 
    } 

    private async void RunLoop() 
    { 
     var i = 0; 
     while (true) 
     { 
      this.label2.Text = $"Enqueued: {this.signal.CurrentCount}"; 
      await this.signal.WaitAsync(); // Wait button click async 
      await Task.Delay(1000); // Simulate work 
      this.label1.Text = $"Completed: {++i}"; 
     } 
    } 

    private void button1_Click(object sender, EventArgs e) 
    { 
     this.signal.Release(); 
     this.label2.Text = $"Enqueued: {this.signal.CurrentCount + 1}"; 
     // Or if you want to limit the # people can queue up, then put this whole 
     // thing in an `if (signal.CurrentCount < myLimit)` block, and optionally 
     // disable the button once limit has been reached, and re-enable it right 
     // before the `WaitAsync` call above. 
    } 
} 
+0

Kann dies nicht zu einer SemaphoreFullException führen, wenn der Benutzer mehrmals klickt, während die Ausführungsschleife abgeschlossen ist? Ich hätte gedacht, dass einer der EventWaitHandle-Klassen angemessener wäre. –

+0

@MartinBrown Ja, nur aktualisierte Antwort, um das zu berücksichtigen. –

+0

Vielen Dank, das hat für mich funktioniert :) –

Verwandte Themen