Autor Beitrag
kmkhl
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 28
Erhaltene Danke: 3

Win 95, Win XP, Win Vista, Win 7, Win 8, Win 8.1
Visual Basic, C#, PHP
BeitragVerfasst: Do 10.10.13 14:52 
MoinMoin

unzwar habe ich vereinfacht gesagt eine WinForm (Form1) und eine Klasse (BeispielKlasse) die Rechnungen macht.
Während BeispielKlasse ihre Rechnungen durchführt, ist Form1 geöffnet und bietet mir die Möglichkeit den Button "Abbrechen" zu drücken.
Ist dieser gedrückt wurden, übergibt er dem bool "abgebrochen" den Wert "true".
Wenn ich jetzt in BeispielKlasse in einer Schleife den Wert von Form1.abgebrochen abfrage, hat dieser immer nur den Anfangswert "false" und wird auch nach einem Klick auf den Button nicht "true" wobei er in der Form1 nach dem Klick "true" wird.

Warum? :shock:
Ich will das die BeispielKlasse bescheid weiß, wenn der Wert von "abgebrochen" "true" wird, damit sie dann aufhört zu rechnen.

Ich danke für Eure Hilfe. :angel:
Ralf Jansen
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 4708
Erhaltene Danke: 991


VS2010 Pro, VS2012 Pro, VS2013 Pro, VS2015 Pro, Delphi 7 Pro
BeitragVerfasst: Do 10.10.13 15:00 
a.) Schaut den deine BeispielKlasse auch auf die Form1 Instanz die angezeigt wird oder kennt die nur irgendeine andere?
b.) Es ist eher schlecht das eine Klasse die nur einer Berechnung von irgendwas dient eine bestimmte Klasse des UserInterfaces kennen muß.
Die Form sollte der Klasse bescheid sagen da hat sich was geändert und nicht umgekehrt sich die Info bei der Form abholen müßen. Im klassischen Design ist es ok wenn die Form die Beispielklasse kennt aber nicht umgekehrt.

Für diesen Beitrag haben gedankt: kmkhl
kmkhl Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 28
Erhaltene Danke: 3

Win 95, Win XP, Win Vista, Win 7, Win 8, Win 8.1
Visual Basic, C#, PHP
BeitragVerfasst: Do 10.10.13 15:09 
"Die Form sollte der Klasse bescheid sagen da hat sich was geändert[...]"

Da wirst du wohl Recht haben, dort werde ich mal anecken und meinen Code umschreiben.
Vielen Dank!
kmkhl Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 28
Erhaltene Danke: 3

Win 95, Win XP, Win Vista, Win 7, Win 8, Win 8.1
Visual Basic, C#, PHP
BeitragVerfasst: Do 10.10.13 15:24 
nein, ich bekomme es einfach nicht hin.

hier mal mein Code:

Form1:
ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
public partial class AusgabeForm : Form
{
        BeispielKlasse bspKlasse = new BeispielKlasse(); 

        public AusgabeForm()
        {
            InitializeComponent();
        }

        private void abbrechenButton_Click(object sender, EventArgs e)
        {
            bspKlasse.abbruch = true;
        }
}


Ausschnitt BeispielKlasse:
ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
public bool abbruch = false;

while (restRechnung != 0 && !abbruch)
{
        rechnen();
}


Moderiert von user profile iconTh69: Codeformatierung überarbeitet.
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19339
Erhaltene Danke: 1752

W11 x64 (Chrome, Edge)
Delphi 12 Pro, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: Do 10.10.13 15:27 
Du musst DoEvents aufrufen, damit die Messages des Buttons ("ich wurde geklickt" usw.) überhaupt verarbeitet werden, die Windows an deine Anwendung schickt:
msdn.microsoft.com/d...cation.doevents.aspx
Das sollte nur nicht zu oft passieren, damit das ganze nicht zu stark verlangsamt wird.
kmkhl Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 28
Erhaltene Danke: 3

Win 95, Win XP, Win Vista, Win 7, Win 8, Win 8.1
Visual Basic, C#, PHP
BeitragVerfasst: Do 10.10.13 15:38 
ausblenden C#-Quelltext
1:
2:
3:
4:
5:
private void abbrechenButton_Click(object sender, EventArgs e)
        {
            bspKlasse.abbruch = true;
            Application.DoEvents();
        }


leider hat das nichts geändert
Ralf Jansen
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 4708
Erhaltene Danke: 991


VS2010 Pro, VS2012 Pro, VS2013 Pro, VS2015 Pro, Delphi 7 Pro
BeitragVerfasst: Do 10.10.13 15:49 
Setz das DoEvents mal in die While Schleife in der du regelmäßig rechnen aufrufst.

Ich frage mich allerdings wenn du bisher kein DoEvents verwendet hast und rechnen auch nicht in einem eigene Thread stattfand wie konnte dann überhaput jemand den Knopf drücken? Eigentlich sollte solange dein rechnen läuft die UI gesperrt sein weil dein Prozess seine gesammte Rechnenzeit in rechnen() verbrät und nie etwas zum Bearbeiten der UI übrig ist. Der Klick auf den Knopf würde so dann eigentlich erst nachdem rechnen() durch ist verarbeitet werden. Und die visuelle Reaktion (das eindrücken des Buttons) auch erst dann sichtbar sein.


Wenn du gleichzeitig eine UI am laufen halten willst und parallel eine Berechnung ausführen willst ist das eine Aufgabe für Threads. DoEvents ist nur eine ganz notdürtige Notlösung (man beachtet die doppelt auftetende Not).
kmkhl Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 28
Erhaltene Danke: 3

Win 95, Win XP, Win Vista, Win 7, Win 8, Win 8.1
Visual Basic, C#, PHP
BeitragVerfasst: Do 10.10.13 15:56 
auch in dem while bringt mich Application.DoEvents(); nicht zur Lösung. Wäre wohl auch zu einfach gewesen.
Ich werde es mal mit Threading probieren.
kmkhl Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 28
Erhaltene Danke: 3

Win 95, Win XP, Win Vista, Win 7, Win 8, Win 8.1
Visual Basic, C#, PHP
BeitragVerfasst: Do 10.10.13 17:00 
gibt es noch eine andere Möglichkeit?
Ralf Jansen
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 4708
Erhaltene Danke: 991


VS2010 Pro, VS2012 Pro, VS2013 Pro, VS2015 Pro, Delphi 7 Pro
BeitragVerfasst: Do 10.10.13 17:04 
Threads sind die Möglichkeit. Für den Anfang würde ich dir den Backgroundworker empfehlen.
kmkhl Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 28
Erhaltene Danke: 3

Win 95, Win XP, Win Vista, Win 7, Win 8, Win 8.1
Visual Basic, C#, PHP
BeitragVerfasst: Do 10.10.13 17:06 
mit dem habe ich auch schon gearbeitet, nur nicht dran gedacht das ich ihn auch hierfür verwenden könnte.
Ich werde es mal versuchen, Danke!
kmkhl Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 28
Erhaltene Danke: 3

Win 95, Win XP, Win Vista, Win 7, Win 8, Win 8.1
Visual Basic, C#, PHP
BeitragVerfasst: Fr 11.10.13 09:42 
:(

es läuft einfach nicht..

..oder besser gesagt es läuft trotzdem weiter -.-

Form1:
ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
public partial class AusgabeForm : Form
{
         BeispielKlasse bspKlasse = new BeispielKlasse(); 

public AusgabeForm()
{
            InitializeComponent();
}
private void startButton_Click(object sender, EventArgs e)
{
      bspKlasse .bw_DoWork(new DoWorkEventArgs(0))
}

private void abbrechenButton_Click(object sender, EventArgs e)
{
            bspKlasse.bw.CancelAsync();
            MessageBox.Show("gestoppt");
            abbrechenButton.Enabled = false;
}
}


Ausschnitt BeispielKlasse:

ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
public BackgroundWorker bw = new BackgroundWorker();

public BeispielKlasse()
{
  bw.WorkerSupportsCancellation = true;
}

public bool bw_DoWork(DoWorkEventArgs e)
{
  while (restRechnung != 0 && !e.Cancel)
  {
    rechnen();
  }  
}
Ralf Jansen
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 4708
Erhaltene Danke: 991


VS2010 Pro, VS2012 Pro, VS2013 Pro, VS2015 Pro, Delphi 7 Pro
BeitragVerfasst: Fr 11.10.13 09:54 
Sieh dir nochmal aus der Hilfe zum Backgroundworker das Codebeispiel an. Insbesondere den Teil wie der Backgroundworker gestartet wird. Du hast zwar einen Backgroundworker erzeugt aber ihn dann gar nicht benutzt sondern einfach die Methode die vom Backgroundworker ausgeführt werden sollte (DoWork) direkt aufgerufen.
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19339
Erhaltene Danke: 1752

W11 x64 (Chrome, Edge)
Delphi 12 Pro, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: Fr 11.10.13 10:11 
Das Beispiel ist allerdings etwas lang muss ich sagen. Deshalb kurz zur Erklärung:
Du musst dem Worker sagen was er asynchron machen soll. Das ist dein bw_DoWork, die Initialisierung findest du in InitializeBackgoundWorker.
Im startAsyncButton_Click siehst du dann den Aufruf über den Worker mit RunWorkerAsync.
kmkhl Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 28
Erhaltene Danke: 3

Win 95, Win XP, Win Vista, Win 7, Win 8, Win 8.1
Visual Basic, C#, PHP
BeitragVerfasst: Fr 11.10.13 11:07 
Ich verzweifle jetzt langsam.


Form1:
ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
    public partial class AusgabeForm : Form
    {
        BeispielKlasse bspKlasse = new BeispielKlasse();

        public AusgabeForm()
        {
            InitializeComponent();
        }

   
        private void Rechnung(object sender, DoWorkEventArgs e)
        {                                 
                    //backgroundWorker starten
                    bspKlasse.bw.RunWorkerAsync();

                    if (bspKlasse.rechner(ersteZahl, zweiteZah))
                    {
                       MessageBox.Show("Rechnung ist richtig");
                    }                                    
        }
         
        private void abbrechenButton_Click_1(object sender, EventArgs e)
        {
            bspKlasse.bw.CancelAsync();
            MessageBox.Show("gestoppt");
            abbrechenButton.Enabled = false;
        }

    }


BeispielKlasse:
ausblenden volle Höhe C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
    public class BeispielKlasse
    {
        public BackgroundWorker bw = new BackgroundWorker();

        public BeispielKlasse()
        {
            InitializeBackgroundWorker();
        }

        private void InitializeBackgroundWorker()
        {
            bw.WorkerSupportsCancellation = true;
            bw.DoWork += new DoWorkEventHandler(bw_DoWork);
            bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bw_RunWorkerCompleted);
        }

        private void bw_DoWork(object sender, DoWorkEventArgs e)
        {
            BackgroundWorker worker = sender as BackgroundWorker;

            e.Result = rechner(?, ?, worker, e);
        }

        public bool rechner(int ersteZahl, int zweiteZahl, BackgroundWorker worker, DoWorkEventArgs e)
        {
            if (worker.CancellationPending)
            {
                e.Cancel = true;
            }
            else
            {
                try
                {
                    [...rechnungen...]

                    while (restGröße != 0)
                    {
                      rechnen();
                    }

                    // Rückgabewert
                    return true;

                }
                catch (Exception Exp)
                {
                    return false;
                }
            }
        }

        private void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            if (e.Error != null)
            {
                MessageBox.Show(e.Error.Message);
            }
            else if (e.Cancelled)
            {
                MessageBox.Show("Canceled");
            }
            else
            {
                MessageBox.Show(e.Result.ToString());
            }
        }
    }


folgende Fehlermeldungen:

in der BeispielKlasse
1. 'public bool rechnung(int ersteZahl, int zweiteZahl, BackgroundWorker worker, DoWorkEventArgs e)': Nicht alle Codepfade geben einen Wert zurück.
2. Keine Überladung für die rechner-Methode nimmt 2 Argumente an.

in Form1
1. Keine Überladung für die Methode 'rechner' nimmt 2-Argumente an.
Ralf Jansen
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 4708
Erhaltene Danke: 991


VS2010 Pro, VS2012 Pro, VS2013 Pro, VS2015 Pro, Delphi 7 Pro
BeitragVerfasst: Fr 11.10.13 11:40 
Zitat:
1. 'public bool rechnung(int ersteZahl, int zweiteZahl, BackgroundWorker worker, DoWorkEventArgs e)': Nicht alle Codepfade geben einen Wert zurück.


Der Codepfad wo du e.Cancel setzt enthalt keinen return deinen Methode erwartet aber das es einen bool als return gibt.


Zitat:
2. Keine Überladung für die rechner-Methode nimmt 2 Argumente an.

Zitat:
1. Keine Überladung für die Methode 'rechner' nimmt 2-Argumente an.


stimmt der hast du ja auch 4 Parameter gegeben. Warum wieso kann ich dir nicht beantworten das war deine Entscheidung. Was der Sinn von ersteZahl, zweiteZahl solltest du schon selbst rausfinden und dann passend übergeben. Da du BackgroundWorker und DoWorkEventArgs mit übergibst sieht das stylistisch von hier auch eher merkwürdig aus. Vielleicht hilft es dir wenn du erstmal die rechner Methode wegläßt und den Code aus rechner direkt in DoWork benutzt.

Das canceln solltest du auch in der while Schleife unterbringen und nicht irgendwo vorher.

Das zuweisen von e.result mit einem Bool finde ich merkwürdig. Du berechnest also irgendetwas das so komplex und langdauernd ist das du es in einen Hintergrundthread auslagerst und das Ergebnis dieser Berechnung ist dann ja bzw. nein?

ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
private void bw_DoWork(object sender, DoWorkEventArgs e)
{
   BackgroundWorker worker = sender as BackgroundWorker;

   while (restGröße != 0)
   {
      if (worker.CancellationPending)
      {
           e.Cancel = true;
           e.Result = null
           return;
      }
      rechnen();
   }
   
   // e.Result mit einem sinnvollen Ergebnis der Berechnung befüllen 
}
Th69
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Moderator
Beiträge: 4805
Erhaltene Danke: 1061

Win10
C#, C++ (VS 2017/19/22)
BeitragVerfasst: Fr 11.10.13 11:45 
Hallo,

die BackgroundWorker-Instanz solltest du besser in der Form-Klasse erstellen (und nicht in deiner Logik-Klasse).

Und die Abfrage auf worker.CancellationPending mußt du natürlich zyklisch innerhalb deiner Rechenmethode durchführen (nicht nur einmalig am Anfang der Methode).

kmkhl hat folgendes geschrieben:
Ich verzweifle jetzt langsam.

Ich auch ;-)
kmkhl Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 28
Erhaltene Danke: 3

Win 95, Win XP, Win Vista, Win 7, Win 8, Win 8.1
Visual Basic, C#, PHP
BeitragVerfasst: Fr 11.10.13 12:18 
Zwischenfrage: Wenn ich bspKlasse.bw.RunWorkerAsync(); ausführe, beginnt er dann automatisch die bw_DoWork(); auszuführen?
Ralf Jansen
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 4708
Erhaltene Danke: 991


VS2010 Pro, VS2012 Pro, VS2013 Pro, VS2015 Pro, Delphi 7 Pro
BeitragVerfasst: Fr 11.10.13 12:22 
RunWorkerAsync erzeigt einen Thread in dem dann der DoWork Event des Backgroundworkers aufgerufen wird. Also wenn deine bw_DoWork dem bw.DoWork Event zugewiesen ist ist die Antwort ja.


Edit: Ich wollte dich schon wieder auf das Codebeispiel in der Hilfe verweisen aber da fehlt dieser Teil dummerweise :( Aber im zweiten Codebeispiel siehst du die InitializeBackgroundWorker Methode wo die Events verdrahtet werden.
kmkhl Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 28
Erhaltene Danke: 3

Win 95, Win XP, Win Vista, Win 7, Win 8, Win 8.1
Visual Basic, C#, PHP
BeitragVerfasst: Fr 11.10.13 12:27 
Das war nur zum testen:

BeispielKlasse:

ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
private void InitializeBackgroundWorker()
{
  bw.DoWork += new DoWorkEventHandler(bw_DoWork);
}

public void bw_DoWork(object sender, DoWorkEventArgs e)
{
  MessageBox.Show("Hallo");
}


Form1:

ausblenden C#-Quelltext
1:
bspKlasse.bw.RunWorkerAsync();					


zeigt aber nichts an :(

Ich danke Euch für Eure Hilfsbereitschaft!