2009-06-30 3 views
0

Haben einige Suchen hier & auf dem 'Netz und haben noch keine gute Antwort gefunden. Was ich versuche, ist ein zweimaliger Aufruf einer Schaltfläche innerhalb derselben Klasse in C#.C# Gewusst wie: Versuchen Sie zweimal in der gleichen Klasse Knopf zu rufen?

Hier ist mein Szenario -

ich ein Formular mit einer Schaltfläche, die sagt „Go“. Wenn ich es das erste Mal anklicke, läuft es durch einige "for" -Schleifen (non-stop), um einen Farbbereich anzuzeigen. Gleichzeitig habe ich die Eigenschaften von button1.Text auf "Stop" gesetzt. Ich möchte den Knopf ein zweites Mal klicken können und wenn das passiert, möchte ich, dass das Programm aufhört. Grundsätzlich ein Stop-and-Go-Button. Ich weiß, wie man es mit 2 Tastenereignissen macht, möchte aber 1 Taste benutzen.

Im Moment ist die einzige Möglichkeit, das Programm zu beenden, der X-Knopf auf dem Formular.

Ich habe verschiedene Dinge ausprobiert und hatte bisher nicht viel Glück, also wollte ich die Gurus hier fragen, wie es geht.

BTW, dies ist eine Modifikation eines Head First Labs C# Buch Übung.

Danke!

~ All

Antwort

7

Sie müssen Multithreading verwenden würden (starten Sie den asynchron intensiven Code Prozess in einem separaten Thread), zum Beispiel mit dem Objekt BackgroundWorker in .NET 2+. Dies ist erforderlich, da Ihre Benutzeroberfläche nicht auf den Klick des Benutzers reagiert, bis die in der Startmethode ausgeführte Schleife abgeschlossen ist. Es ist ziemlich irrelevant, wenn Sie die gleiche Schaltfläche oder eine andere Schaltfläche verwenden, um den Prozess umzuschalten, da der Prozessor gerade mit der Verarbeitung der Schleife beschäftigt ist. Die BackgroundWorker hat eine Eigenschaft namens WorkerSupportsCancellation, die in diesem Szenario wahr sein muss. Wenn der Benutzer auf Stop klickt, wird die CancelAsync-Methode der BackgroundWorker aufgerufen.

Siehe MSDN für ein gutes Beispiel. Auch DreamInCode hat ein gutes Tutorial, das Ihrer Anforderung sehr ähnlich ist.

+0

Guter Punkt! OP hat möglicherweise vergessen, dies auch zu implementieren. –

+0

Ah, das klingt nach einer großartigen Idee. Auch hier bin ich noch nicht zu den BackgroundWorker-Infos gekommen, werde mich aber darum kümmern und sehen, wie das funktioniert. Danke für den tollen Input. – Valien

+0

Gern geschehen, Valien! Wenn Sie anfangen, sich mit Multithreading zu beschäftigen, werden Sie von der Anfängerstufe zur Zwischenstufe der Kompetenz fortgeschritten sein (die meisten Entwickler halten das richtige Verständnis von Threads für einen Meilenstein). Nimm es langsam und du solltest kein Problem haben. :-) – Cerebrus

3

Warum nicht zwei Tasten, eine verstecken, wenn die anderen sichtbar ist? Das sollte viel einfacher zu handhaben sein.

Oder Sie können ein Bool-Feld hinzufügen, um anzugeben, welcher Operationszweig ausgeführt werden soll.

+0

Cool! Ich wusste nicht, dass du das kannst (daher bin ich noch ein Newb :)) Ich werde es ausprobieren! – Valien

+0

Seien Sie vorsichtig, wenn Sie die Straße der versteckten Kontrollen hinuntergehen. Es kann die Arbeit mit dem Winforms-Designer, einen der größten Vorteile von Winforms, zu einer Übung in Agonie machen, wenn es zur Entwurfszeit überstrapaziert wird. –

+0

Wenn Sie auf diese Weise vorgehen, müssen Sie beide Schaltflächen so positionieren, dass sie im Designer sichtbar sind, und dann in Ihrem Form_Load-Ereignis btnStart.Location = btnStop.Location, damit sie sich an der gleichen Position in Ihrem ausführenden Formular befinden. –

3

Eine einfache Lösung wäre, ein boolesches Element zu Ihrem Formular hinzuzufügen, z. B. true, wenn die Schaltfläche "Go" und false sagt, wenn die Schaltfläche "Stop" sagt.

Überprüfen Sie dann im Ereignishandler Ihrer Schaltfläche diesen booleschen Wert. Wenn der Wert true ist, starten Sie Ihre Operation und setzen Sie den Wert auf false, wenn Sie den Text der Schaltfläche ändern, um "stop" zu sagen. Umgekehrt für den anderen Fall. :)

Es gibt andere Techniken, die ich vielleicht vorziehen würde, wenn dies Produktionscode wäre, vielleicht unter Berücksichtigung der Gestaltung der Form sorgfältiger, aber da dies eindeutig eine Lernübung ist glaube ich, dass eine einfache boolesche Flagge die aktuelle angibt Zustand des Formulars ist genau das, wonach Sie suchen.

Beachten Sie, dass ich Ihnen dringend davon abraten sollte, den Wert des Schaltflächentextes zu überprüfen, um festzustellen, in welchem ​​Zustand sich das Objekt befindet. Wenn immer möglich, möchten Sie, dass Ihr visueller Zustand "entkoppelt" wird den Status Ihres zugrunde liegenden Objekts. Das heißt, Ihre visuellen Widgets können von Ihren zugrunde liegenden Objekten abhängen, aber Ihre zugrunde liegenden Objekte sollten nicht von Ihren visuellen Widgets abhängen. Wenn Sie den Text der Schaltfläche getestet haben, hängt Ihre zugrundeliegende Logik von Ihrem visuellen Zustand ab und dies würde gegen diese allgemeine Regel verstoßen.

Wenn Ihr Problem mit der Tatsache zusammenhängt, dass Sie den Vorgang nicht abbrechen können, während er ausgeführt wird, sollten Sie sich mit einem BackgroundWorker befassen, um Ihre lang andauernde Aktivität auszuführen.

0

Sie können die Eigenschaft Tag auf der Schaltfläche auf einen booleschen Wert setzen, der angibt, ob die nächste Aktion "Stop" oder "Go" sein soll, und sie jedes Mal zurücksetzen, wenn Sie auf die Schaltfläche klicken. Es handelt sich jedoch um eine Object-Eigenschaft. Sie müssen sie daher beim Lesen in bool umsetzen.

1

würde Eine andere Möglichkeit, den aktuellen Text auf dem Knopf zu überprüfen, um zu bestimmen, was zu tun ist:

void btnStartStop_Click(Object sender, EventArgs e) 
{ 
    if (btnStartStop.Text == "Go") 
    { 
     btnStartStop.Text = "Stop"; 

     // Go code here 

    } 
    else 
    { 
     btnStartStop.Text = "Go"; 

     // Stop code here 

    } 
} 
+1

Bitte tun Sie dies nicht (Begründung in meiner Antwort). –

+0

Ich persönlich würde nicht, aber es funktioniert und es ist einfach –

+0

In einigen Fällen ist das in Ordnung ... Nur sollten Sie die Zeichenfolgen in die konstanten Felder, so dass Sie nicht eine Änderung in mehreren Orten das nächste Mal tun müssten. –

1

Erhalten Sie Ihr zweites Knopfklickereignis? Setzen Sie einen Haltepunkt in Ihren Klick-Handler und führen Sie Ihren Code aus. Wenn du das zweite Mal klickst, hast du deinen Breakpoint geknackt?

Wenn Ihre Schleife kontinuierlich ausgeführt wird und sich in Ihrem Button-Click-Handler befindet, wird Ihre Schleife im UI-Thread ausgeführt. Wahrscheinlich werden Sie den zweiten Knopfdruck erst sehen, wenn die Schleife abgeschlossen ist. Versuchen Sie zusätzlich zu dem oben angezeigten Verzweigungscode, entweder DoEvents in Ihre Schleifenverarbeitung einzufügen (dies ist ein Ort, an dem Ihre Schleife temporär die Kontrolle aufgibt, damit Nachrichten verarbeitet werden können). Oder (besser) werfen Sie einen Blick auf die Klasse backgroundworker - führen Sie den Großteil Ihrer Verarbeitung in einem anderen Thread aus, damit Ihre Benutzeroberfläche auf Schaltflächenklicks reagieren kann.

+0

DoEvents ist schlecht, +1 für die Klasse von Backgroundworker, obwohl –

+1

@Patrick Ich stimme zu DoEvents zu - Meldungsschleife Reentrancy ist im Allgemeinen keine gute Sache. Es ist jedoch ein schneller Weg, um festzustellen, dass dies das Problem ist, ohne viel Code-Umstrukturierung zu erfordern. Dann kann er zu einer besseren Lösung wechseln (Hintergrundarbeiter, Threadpool usw.). Da er sich selbst als Neuling identifizierte, wollte ich ihn nicht sofort mit Threads schlagen. – JMarsch

1

Cerebrus hat recht, wenn er den Background Worker Thread verwendet. Wenn Sie jedoch eine WPF-App ausführen, kann die Benutzeroberfläche nicht direkt aktualisiert werden. Um dies zu umgehen, können Sie Dispatcher.BeginInvoke auf der Hauptsteuerung/Fenster aufrufen.

Gegeben Code wie:

Private Delegate Sub UpdateUIDelegate(<arguments>) 

Private Sub CallUpdateUI(<arguments>) 
    control.Dispatcher.BeginInvoke(Windows.Threading.DispatcherPriority.Background, New UpdateUIDelegate(AddressOf UpdateUI), <arguments>) 
End Sub 

Private Sub UpdateUI(<arguments>) 
    'update the UI 
End Sub 

Sie CallUpdateUI aus dem Hintergrund Worker-Thread aufrufen können, und es wird den Haupt-Thread ausführen UpdateUI bekommen.

+0

Genau genommen ist Invoke notwendig, auch wenn Sie keine WPF-App entwickeln. Es ist das grundlegende Prinzip von Win32 Multithreading - Aktualisieren Sie nie UI auf einem sekundären Thread. +1 für die genaue Antwort. – Cerebrus

Verwandte Themen