Laden...

timer und Label(thread)

Erstellt von DasShrike vor 17 Jahren Letzter Beitrag vor 17 Jahren 5.848 Views
D
DasShrike Themenstarter:in
79 Beiträge seit 2006
vor 17 Jahren
timer und Label(thread)

Hallo
ich habe da mal ne Frage zu Threads:
Ich habe nen timer der alle 100 ms einem Label nen neuen Wert zuweisen soll.
ur bekomme ich immer ne Fehlermeldung:

Cross-thread operation not valid: Control 'label1' accessed from a thread other than the thread it was created on.

Kann ich ja auch verstehen, aber was kann man denn da machen?


.....
int wert=0;
........

 private void test(object sender, System.Timers.ElapsedEventArgs e)
        {
            wert=wert+1;
            label1.Text= wert.ToString();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            System.Timers.Timer ti = new System.Timers.Timer();
        
           ti.Interval = 100;
            ti.Elapsed+=new System.Timers.ElapsedEventHandler(test);
            ti.Start();
        }

MfG Daniel

R
402 Beiträge seit 2005
vor 17 Jahren

hi,die fehlermeldung bedeudet: Dass du dein label aus einem anderen thread heraus veränderst als von dem du es erzeugt hast.
bps: main-thread: erstellt das label(er zeichnet es), dein-eigener-thread:verändert es, dass ist in c# verboten,da es dadurch zu nicht vorhersehbaren situationen kommen kann.

poste mal mehr code,dann können wir dir zeigen wo der fehler genau liegt!
lg rizi

M
1.439 Beiträge seit 2005
vor 17 Jahren

Control.Invoke

D
DasShrike Themenstarter:in
79 Beiträge seit 2006
vor 17 Jahren

Ja super Danke hat funktioniert!!!



        private void test(object sender, System.Timers.ElapsedEventArgs e)
        {
            wert=wert+1;
            label1.Invoke(new MethodInvoker(neuTest));       
        }

       private void neuTest()
        {
            label1.Text = wert.ToString();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            System.Timers.Timer ti = new System.Timers.Timer();
        
           ti.Interval = 100;
            ti.Elapsed+=new System.Timers.ElapsedEventHandler(test);
            ti.Start();
            
        }

49.485 Beiträge seit 2005
vor 17 Jahren

Hallo DasShrike,

der Vollständigkeit halber: FAQ: Controls von Thread aktualisieren lassen (Invoke-/TreeView-Beispiel)

herbivore

R
402 Beiträge seit 2005
vor 17 Jahren

hi,mir ist aber nicht ganz klar wo er einen neuen thread erstellt???
würde mich interessieren!
lg rizi

49.485 Beiträge seit 2005
vor 17 Jahren

Hallo rizi,

System.Timers.Timer erstellt den Thread (bzw. benutzt einen Thread aus dem ThreadPool).

Ist aber ein guter Hhinweis, denn: Für Windows-Forms-Anwendungen sollte man immer System.Windows.Forms.Timer verwenden. Dann spart man sich auch das Invoke!

herbivore

L
11 Beiträge seit 2006
vor 17 Jahren

Hi.

Eine Frage zu dem Teil:


private void neuTest()
        {
            label1.Text = wert.ToString();
        }

Was mache ich, wenn ich der Methode den "wert" direkt übergeben will?
Also:


private void neuTest(string wert)
        {
            label1.Text = wert.ToString();
        }

Gruß LordGabriel

49.485 Beiträge seit 2005
vor 17 Jahren

Hallo LordGabriel,

ich verstehe die Frage nicht. Die Antwort hast du doch schon selbst gelesen, mal abgesehen davon, dass ToString bei einem String überflüssig ist.

herbivore

L
11 Beiträge seit 2006
vor 17 Jahren

Also:

Mein Problem sieht so aus:
Ein Thread läuft.
Er soll ein einer GUI in eine RichTextBox schreiben.
Das die GUI das mitbekommt, habe ich mit Events gelöst.
Jetzt bin ich in der GUI und will was reinschreiben.
Deswegen:


private void schreibe(string mesage)
{
richtextbox.AppendText(message);
}

Nur wie sieht jetzt der Aufruf aus, mit dem ich die Message übergebe?


private void eineMethode(blablabla)
{
richtextbox.Invoke(new MethodInvoker(???????));
}

Gruß LordGabriel

P.S.: Ist schon klar, dass man einen String nicht mit ToString() umwandeln muss!
Es sollte nur dem Wiedererkennungswert dienen! 😉

49.485 Beiträge seit 2005
vor 17 Jahren

Hallo LordGabriel,

für die Fragezeichen musst du die aufrurufende Methode angeben.

Für ein Beispiel siehe FAQ: Controls von Thread aktualisieren lassen (Invoke-/TreeView-Beispiel)

herbivore

L
11 Beiträge seit 2006
vor 17 Jahren

Ja, das ist ja klar:


private void eineMethode(blablabla)
{
richtextbox.Invoke(new MethodInvoker(schreibe));
} 

private void schreibe(string message)
{
richtextbox.AppendText(message);
}

Aber wie übergebe ich der Methode die Nachricht? Direkt in den MethodInvoker geht ja nicht.
Irgendwie finde ich unter dem Link keine Lösung für mich. (Oder ich sehe vor lauter Bäumen den Wald nicht?!)

Gruß LordGabriel

49.485 Beiträge seit 2005
vor 17 Jahren

Hallo LordGabriel,

es gibt mehr als eine Überladung von Control.Invoke. Verwende eine, bei der du Paramter (als Object-Array) übergeben kannst. Du kannst das nicht den MethodInvoker-Delegaten nehmen, sondern musst einen (eigenen) nehmen, der die entsprechenden Parameter hat.

herbivore

96 Beiträge seit 2006
vor 17 Jahren

Hi LordGabriel,

Habe exakt das selbe Problem. Hast du bereits den Code dafür? Verstehe nicht wie ich ein Object-Array, wie von herbivore vorgeschlagen, in diesem Fall anwenden kann.

49.485 Beiträge seit 2005
vor 17 Jahren

Hallo Vido,

hast du dir schonmal die andere Überladung von Control.Invoke angeguckt?

herbivore

96 Beiträge seit 2006
vor 17 Jahren

Hi herbivore

Meinst du: http://msdn2.microsoft.com/en-us/library/system.windows.forms.control.invoke(d=ide).aspx ?

Dort finde ich den Weg über delegate und ohne MethodeInvoker. Ich dachte entweder MethodInvoker oder Delegate? Und hier wurde mit Methodinvoker angefangen.

49.485 Beiträge seit 2005
vor 17 Jahren

Hallo Vido,

MethodInvoker ist ein (bestimmter) Delegat. Und MethodeInvoker ist - wie ich schon schieb - nicht passend für den Aufruf mit Parametern. Vergiss MethodInvoker (oder guck in die Doku, um zu sehen, warum du MethodInvoker vergessen sollst 🙂

Außerdem ist in der von dir genannten Doku ein Codebeispiel zum Aufruf einer Methode mit Parametern. Was willst du denn noch mehr?

herbivore

96 Beiträge seit 2006
vor 17 Jahren

Also ich vertraue dir blind und verwende keinen MethodInvoker.

Das Beispiel aus der Doku verwirrt mich aber etwas... Ich kam auf dieses Problem, da ich einen neuen Thread startete, dort ein Bild holte und dann in den Haupt-Thread einfügen wollte. Da kam bei mir auch die Meldung, dass ich einen Cross-Thread mache und das nicht erlaubt ist, die du ja bereits vorher erklärt hast und mir auch einleuchtet.
Das Beispiel in der Doku erstellt aber erst einen Thread und erstellt gar neue instanzen. Bin ich mit diesem Code ganz falsch:


public void set_userpicture(Image userpicture)
        {
            if (this.userpic.InvokeRequired)
            {
                userpic.Invoke(new userpic_handler(set_userpicture), new Object[] { userpicture });
            }
            else
                userpic.Image = userpicture;
            
            this.userpic.Image = userpicture;


        }

        private delegate void userpic_handler(Image userpicture);

49.485 Beiträge seit 2005
vor 17 Jahren

Hallo Vido,

diese Zeile ist zu viel:


this.userpic.Image = userpicture;

Ansonsten sieht es doch gut aus.

herbivore

96 Beiträge seit 2006
vor 17 Jahren

na toll: ein Flüchtigkeitsfehler...😉

Klappt! Danke!