Laden...

Text auf Button setzen hat keine Auswirkung

Erstellt von M.Lach vor 5 Jahren Letzter Beitrag vor 5 Jahren 2.686 Views
M
M.Lach Themenstarter:in
33 Beiträge seit 2008
vor 5 Jahren
Text auf Button setzen hat keine Auswirkung

Hallo,

ich möchte den vorhandenen Text des Buttons von "play" auf "stop" setzten, wenn dieser gedrückt wurde.
dazu habe ich folgendes eingebaut:
Windows-Form-Anwendung unter VS2017:

private void button1_Click_1(object sender, EventArgs e)
        {
            if (button1.Text == "play")
            {
                textBox1.Enabled = false;
                comboBox1.Enabled = false;
                button1.Text = "stop";

              ......noch mehr code....... 

In der Initalisierung und in den Properties ist der Text des Buttons auf "play" gesetzt worden.
Nehme ich ein frisches Projekt und mache dort das gleiche, dann funktioniert das.
Auch funktionieren alle anderen beiden Anweisungen im Beispiel oben.
Nehme ich alle Funktionen - bis auf die Zeile "button1.text = "xxx";" raus, ändert sich der Text komischer weise. Auch wenn es die erste Zeile wird.
Wo kann ich nun weiter suchen, warum der Text nicht geändert wird?

--

Mit freundlichen Grüßen,

Matthias Lach

5.657 Beiträge seit 2006
vor 5 Jahren

Mit Hilfe des Debuggers kannst du herausfinden, von welchen Steuerelementen aus dieser Eventhandler aufgerufen wird. Setz dir einen Breakpoint, und wenn dort angehalten wird, schau dir den Inhalt von sender an. So kannst du nachvollziehen, was in deinem Code in welcher Reihenfolge abläuft.

Weeks of programming can save you hours of planning

T
2.219 Beiträge seit 2008
vor 5 Jahren

Anstelle einer Textprüfung wäre es sauberer wenn sich dein Form den aktuellen Zustand merkt.
Hier wäre ein bool mit dem aktuellen Zustand für isPlaying z.B. eine bessere Form.
Wenn es mehr zustände gibt, wäre auch ein Enum hilfreich.
Texte können sich mit der Zeit auch mal ändern, bei Mehrsprachigkeit wäre es sogar fatal alle Sprachen durchprüfen zu wollen.

T-Virus

Developer, Developer, Developer, Developer....

99 little bugs in the code, 99 little bugs. Take one down, patch it around, 117 little bugs in the code.

M
M.Lach Themenstarter:in
33 Beiträge seit 2008
vor 5 Jahren

hallo, und danke für die Antworten.

Ja, die Art ist nicht sauber, aber mehr behersche ich leider (noch) nicht. Funktioniert aber (normalerweise). Was mich wundert: Mit dem Debugger sehe ich nichts. Evtl. kann ich das gesehene aber auch gar nicht auswerten. Fehlendes Wissen ist hier wohl die Ursache.

Anmerkung: Setzte ich direkt nach der Zeile " button1.Text = "stop";" eine Messagebox, dann funktioniert das wie gewünscht: Der Text ändert sich sofort nach dem Einsprung in die IF-Schleife, also rein optisch. Ohne diese Message-Box-Ausgabe habe ich das "Gefühl", das erst alle anderen Sachen in der Schleife abgearbeitet werden, und der Text im Button erst später geändert wird. Denn vor verlassen der IF-Schleife habe ich dann wieder den Text auf "play" geändert. Und das sieht dann danach aus, als ob das alles zu schnell hinter einander passiert, und man das setzten auf "stop" gar nicht mit bekommt. Diese letzte "auf play zurück setzten" habe ich testweise mal heraus genommen und das bestätigt das "Gefühl". Erst passiert alles Andere, dann wird der Text angepasst. Oder besser: Wird die Änderung sichtbar. Was kann man machen, damit direkt nach dem setzten des Textes dieser auch angezeigt wird und verwendet wird?

--

Mit freundlichen Grüßen,

Matthias Lach

D
152 Beiträge seit 2013
vor 5 Jahren

Das liegt wohl daran das dein UI blockiert.
[FAQ] Warum blockiert mein GUI?

3.825 Beiträge seit 2006
vor 5 Jahren

Der Text im Button wird erst geändert wenn die Methode beendet wird.

Was kommt denn noch bei "......noch mehr code......." ?

Lass das mal alles weg was danach kommt.

Grüße Bernd

Workshop : Datenbanken mit ADO.NET
Xamarin Mobile App : Finderwille Einsatz App
Unternehmenssoftware : Quasar-3

M
368 Beiträge seit 2006
vor 5 Jahren

Weiters kann man auch hier bei Irrklang spicken, Beispielcode von Projekt Nr. 6:


...
// pauses or unpauses the currently playing sound
		private void PauseButton_Click(object sender, System.EventArgs e)
		{
			if (currentlyPlayingSound != null)
			{
				currentlyPlayingSound.Paused = !currentlyPlayingSound.Paused;
				UpdatePauseButtonText();
			}
		}


		// Updates the text on the pause button
		private void UpdatePauseButtonText()
		{
			if (currentlyPlayingSound != null)
			{
				if (currentlyPlayingSound.Paused)
					PauseButton.Text = "Play";
				else
					PauseButton.Text = "Pause";
			}
			else
				PauseButton.Text = "";
		}
...

Goalkicker.com // DNC Magazine for .NET Developers // .NET Blogs zum Folgen
Software is like cathedrals: first we build them, then we pray 😉

M
M.Lach Themenstarter:in
33 Beiträge seit 2008
vor 5 Jahren

wenn ich alles auskommentiere, und nur das "text = "xxx" nutze, dann geht da auch.
Ich gucke mir das Thema mit dem blockierten GUI mal an und versuche das umzusetzen.

--

Mit freundlichen Grüßen,

Matthias Lach

M
M.Lach Themenstarter:in
33 Beiträge seit 2008
vor 5 Jahren

auch wenn es nicht "sauber" ist, hier mal der komplette Code vom Button1:


        private void button1_Click_1(object sender, EventArgs e)
        {
            if (button1.Text == "play")
              { 
                button1.Text = "stop"; // und DAS passiert nicht sofort, sondern erst wenn der Sound fertig ist!
                textBox1.Enabled = false;
                comboBox1.Enabled = false;
                var song = textBox1.Text;
                int output = comboBox1.SelectedIndex;

                ISoundDeviceList sndDev = new ISoundDeviceList(SoundDeviceListType.PlaybackDevice);
                ISoundEngine engine = new ISoundEngine(SoundOutputDriver.AutoDetect, SoundEngineOptionFlag.DefaultOptions, sndDev.getDeviceID(output));

                try
                {
                    engine.Play2D(song, false);
                }
                catch (Exception ex)
                {
                    MessageBox.Show(ex.Message);
                }
                while (engine.IsCurrentlyPlaying(song) == true)
                {
                    Thread.Sleep(500);
                }
                engine.RemoveSoundSource(song);
               //  button1.Text = "play"; // ist zu schnell erledigt, da der Song zu erst gespielt wird - optisch sieht man das nie.
                textBox1.Enabled = true;
                comboBox1.Enabled = true;
              }

            else if (button1.Text == "stop")
              { 
                //engine.currentlyPlayingSound.Stop();
                //engine.RemoveSoundSource(song);
                MessageBox.Show("Stop by stop");
                button1.Text = "play";

              }

Was mich noch irritiert: Warum wird das nicht der strengen Reihenfolge nach abgearbeitet? Ich dachte: Wenn der Button gedrückt wird läuft das Zeile für Zeile von oben nach unten runter und die Sachen sind auch in der Reihenfolge erkennbar. Da das "Button1.text = ..." zuerst steht, sollte doch die Änderung des Buttons sofort nach dem drücken sichtbar werden? Es wird aber das MP3 zu erst gespielt, dann der Text vom Button geändert. Warum könnte das so sein? Als wohl blutiger Anfänger erkenne ich das so leider nicht.

Das Thema mit "sauber" programmieren werde ich dann gerne mal lernen und das kleine Projekt hier dazu nutzen um Eure Vorschläge umzusetzen.
Danke schon mal für die Unterstützung und die Geduld mit mir.

--

Mit freundlichen Grüßen,

Matthias Lach

T
2.219 Beiträge seit 2008
vor 5 Jahren

Das Problem ist, dass dein Event erst einmal durchlaufen sein muss, damit die UI auch neu gerendert werden kann.
Da du aber auch eine while schleife hast, die dann noch per Thread.Sleep rund 0,5 Sekunden warten muss, friert auch deine UI solange ein, bis dein Sound abgespielt wurde.

Solche Dinge lässt man mit einem Hintergrund Thread machen bzw. in diesem Fall mit einem BackgroundWorker.
Dann musst du dir aber auch mal den Link anschauen, den david.m dir gepostet hat.
Da wird das Problem, dass sehr häufig vorkommt, behandelt und dir Wege aufgezeigt, wie es gelöst werden kann.

T-Virus

Developer, Developer, Developer, Developer....

99 little bugs in the code, 99 little bugs. Take one down, patch it around, 117 little bugs in the code.

5.657 Beiträge seit 2006
vor 5 Jahren

Mach es dir doch nicht unnötig kompliziert. Wenn das Beispiel bei dir funktioniert - warum solltest du denn dann noch Thread.Sleep einbauen?

Das Fenster wird, wie T-Virus schon gesagt hat, erst neu gezeichnet, wenn alle Events abgearbeitet sind. Und das ist bei dir eben erst frühestens nach 500ms der Fall. Wenn du wissen willst, warum das so ist, und wie das alles "unter der Haube" funktioniert, schau dir mal ein Buch zum Thema WinForms an~~:::

* Hab ich das entsprechende Kapitel übersehen, oder gibt es in dem Buch nur eine Einführung in WPF?

Weeks of programming can save you hours of planning

T
2.219 Beiträge seit 2008
vor 5 Jahren

@MrSparkle
In den neueren Büchern wird nur noch WPF behandelt.
Im 2008 gab es noch Windows Forms Kapitel.

Link:
http://openbook.rheinwerk-verlag.de/visual_csharp/visual_csharp_13_001.htm

T-Virus

Developer, Developer, Developer, Developer....

99 little bugs in the code, 99 little bugs. Take one down, patch it around, 117 little bugs in the code.

M
M.Lach Themenstarter:in
33 Beiträge seit 2008
vor 5 Jahren

Hab nun versucht alles Funktionen zu "bauen".

eine zum sound abspielen, 2 zum buttontext anpassen.

Nun habe ich das Problem, das ich die Variablen nicht in die Funktion bekomme, bzw wenn ich im neuen Thread auf die Werte der Combobox zugreife eine Exeption bekomme.
(Komischerweise mit deutschem Fehlertext, obwohl VS auf englisch steht.)
$exception {"Ungültiger threadübergreifender Vorgang: Der Zugriff auf das Steuerelement comboBox1 erfolgte von einem anderen Thread als dem Thread, für den es erstellt wurde."} System.InvalidOperationException.
Ich versuche gerade ein Thema zu finden, das die Übergabe von Werten an den Thread beahndelt.
Das muss, soweit ich herausgefunen habe, beim "new Thread" mit übergeben werden.
Doof, das ich die Engine im neuen Thread erzeuge, und in anderen Funktionen drauf zugreife mag.....
(suche noch)...

der Code sieht nun so aus:



void soundausgeben ()
        {
            var song = textBox1.Text;
            int output = comboBox1.SelectedIndex;
            ISoundDeviceList sndDev = new ISoundDeviceList(SoundDeviceListType.PlaybackDevice);
            ISoundEngine engine = new ISoundEngine(SoundOutputDriver.AutoDetect, SoundEngineOptionFlag.DefaultOptions, sndDev.getDeviceID(output));

            try
            {
                engine.Play2D(song, false);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
            engine.RemoveSoundSource(song);
            this.Invoke((Action)buttonplaysetzten);
        }

        void buttonplaysetzten()
        {
            button1.Text = "play";
            textBox1.Enabled = true;
            comboBox1.Enabled = true;
            engine.currentlyPlayingSound.Stop();
            engine.RemoveSoundSource(song);
            MessageBox.Show("Stop by buttonplaysetzten"); //zum testen
        }

        void buttonstopsetzen ()
        {
            button1.Text = "stop";
            textBox1.Enabled = false;
            comboBox1.Enabled = false;
        }

        private void button1_Click_1(object sender, EventArgs e)
        {
            if (button1.Text == "play")

            {
                buttonstopsetzen ();               
                new Thread(soundausgeben).Start () ;
              }
            else if (button1.Text == "stop")
              {
                buttonplaysetzten();
              }
         }
        }

--

Mit freundlichen Grüßen,

Matthias Lach

1.040 Beiträge seit 2007
vor 5 Jahren

(Komischerweise mit deutschem Fehlertext, obwohl VS auf englisch steht.)

Die Sprache der Fehlermeldungen hat mit der Sprache des VS nichts zu tun.
Es gibt für das .NET Framework Language Packs, es reicht wenn du das entsprechende Language Pack für deutsch deinstallierst.

M
M.Lach Themenstarter:in
33 Beiträge seit 2008
vor 5 Jahren
Infos über Grundlagen: hier: Methoden und Parameterübergabe

Habe mal versucht mir was anzulesen.
https://docs.microsoft.com/de-de/dotnet/csharp/programming-guide
oder auch
http://openbook.rheinwerk-verlag.de/visual_csharp/visual_csharp_09_001.htm

Also die "Funktionen" sind in c# dann wohl eher "Methoden". Diese haben Deklarationen über "Zugriffsebene"... usw usw ... viel Zeug gelesen, nix verstanden. Selbst wenn ich keinen neuen Thread erzeuge bekomme, in meinem Projekt, bekomme ich das so nicht hin, da mir wohl Grundlagen fehlen und ich die Konsole-Beispeiel, die immer angegeben werden nicht verstehe. Bzw. nicht so umsetzten kann, wie ich es gerne hätte. Als Lerntyp bin ich eher so der Visuelle-Typ.... Mir helfen konkrete Beispiele mit Erklärungen dazu.

Wie bekomme ich von der erzeugten "Engine" einen Aufruf hin und kann als Parameter das Output-Device und den Titel übergeben?
Wenn ich "engine" in anderen Methode aufrufe, wissen die nicht was damit gemeint ist und sagen mit dann: > Fehlermeldung:

The name 'engine' does not exist in the current context

Und wenn ich das alles wie zuvor in einem "Rutsch" mache, dann hab ich das "GUI blockerit"-Thema.

--

Mit freundlichen Grüßen,

Matthias Lach

K
166 Beiträge seit 2008
vor 5 Jahren

Stichwort Scope: Scopes in C#


        void buttonplaysetzten()
        {
            button1.Text = "play";
            textBox1.Enabled = true;
            comboBox1.Enabled = true;
            engine.currentlyPlayingSound.Stop();
            engine.RemoveSoundSource(song);
            MessageBox.Show("Stop by buttonplaysetzten"); //zum testen
        }

das Objekt "engine" gibt es in der Methode buttonplaysetzen nicht.
Entweder du gibst es als Parameter mit in die Methoden, oder Intitialisierst es als Klassenvariable, was aber eigentlich auch bad practise ist.

Bsp:



void MethodeXYZ()
{
ISoundEngine engine = new ISoundEngine(SoundOutputDriver.AutoDetect, SoundEngineOptionFlag.DefaultOptions, sndDev.getDeviceID(output));

buttonplaysetzten(engine);
}

void buttonplaysetzten(ISoundEngine engine)
        {
            button1.Text = "play";
            textBox1.Enabled = true;
            comboBox1.Enabled = true;
            engine.currentlyPlayingSound.Stop();
            engine.RemoveSoundSource(song);
            MessageBox.Show("Stop by buttonplaysetzten"); //zum testen
        }

K
166 Beiträge seit 2008
vor 5 Jahren

Und wenn ich das alles wie zuvor in einem "Rutsch" mache, dann hab ich das "GUI blockerit"-Thema.

Das wirst du auch weiterhin haben, solange du nicht [FAQ] Warum blockiert mein UI beachtest....

F
10.010 Beiträge seit 2004
vor 5 Jahren

Selbst wenn ich keinen neuen Thread erzeuge bekomme, in meinem Projekt, bekomme ich das so nicht hin, da mir wohl Grundlagen fehlen und ich die Konsole-Beispeiel, die immer angegeben werden nicht verstehe. Bzw. nicht so umsetzten kann, wie ich es gerne hätte.

Als Lerntyp bin ich eher so der Visuelle-Typ.... Mir helfen konkrete Beispiele mit Erklärungen dazu.

Und du merkst das deine Herangehensweise hier vollkommen falsch ist.

Lern doch erstmal die Grundlagen.
Meinst du das Du das, was ein Professioneller Programmierer in 1-2 Jahren von Grund auf lernt in ein paar Stunden ansehen kannst?