[C#] Form1.toolStripStatusLabel1 ändern aus anderer Klasse heraus?

flokli

Erfahrenes Mitglied
Hallo,

probiere jetzt mal C# aus, habe nur ein Problem mit der (Sichtbarkeit?) der Unterklassen/Methoden in einer Form.

Form1.cs
enthält u.a. eine Statusleiste (toolStripProgressBar1, toolStripStatusLabel1).
Jetzt wird mit aus Form1.cs die Klasse in pinger.cs gestartet (als neuer Thread):

pinger.cs:
Code:
using System;
using System.Collections.Generic;
using System.Net;
using System.Net.NetworkInformation;
using System.Text;
using System.Windows.Forms;

namespace idea
{
    class pinger
    {
        private string host;
        public pinger(string host_str)
        {
            host = host_str;
        }

        public void do_ping()
        {
            try
            {
                //A
                Ping pingSender = new Ping();
                PingOptions options = new PingOptions();

                // Use the default Ttl value which is 128,
                // but change the fragmentation behavior.
                options.DontFragment = true;

                // Create a buffer of 32 bytes of data to be transmitted.
                string data = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
                byte[] buffer = Encoding.ASCII.GetBytes(data);
                int timeout = 120;
                PingReply reply = pingSender.Send(host, timeout, buffer, options);
                string message = "";
                if (reply.Status == IPStatus.Success)
                {
                    message += "Address: {0}" + reply.Address.ToString();
                    message += "\nRoundTrip time: {0}" + reply.RoundtripTime;
                    message += "\nTime to live: {0}" + reply.Optionsl;
                    message += "\nDon't fragment: {0}" + reply.Options.DontFragment;
                    message += "\nBuffer size: {0}" + reply.Buffer.Length;
                }
                System.Windows.Forms.MessageBox.Show(message);
            }
            catch
            {
                System.Windows.Forms.MessageBox.Show("PC aus.");
            }
            //B
            System.Threading.Thread.CurrentThread.Abort();
        }
    }
}

Hier der Aufruf:
Code:
pinger tws = new pinger(e.Node.Text);
                Thread t = new Thread(new ThreadStart(tws.do_ping));
                t.Start();

Jetzt will ich bei //A und //B die Statusbar-Elemente ändern.
Dazu habe ich in Form1.cs folgende Methode:
Code:
public void statusbar(bool visible_progressbar, int progress, bool visible_label, string label_text)
        {
            toolStripProgressBar1.Visible = visible_progressbar;
            toolStripProgressBar1.Value = progress;
            toolStripStatusLabel1.Visible = visible_label;
            toolStripStatusLabel1.Text = label_text;
        }
Wenn ich jedoch jetzt versuche, in //A
Code:
Form1.statusbar(true,100,true,"Pinge Host...");
aufzurufen und in //B das,
Code:
Form1.statusbar(false, 0, false, "");
kommt es zu einem CS0120.

Was mache ich falsch?
 
Hi!

Du versuchst zudem von einem fremden Thread aus auf ein Control zuzugreifen, was vermieden werden sollte. Du musst also dafür sorgen, dass deine Controls nur von Thread verändert werden, in dem Sie erstellt wurden. Warum erfährst in meinem [thread=260455]Multi-Threading - Teil1: Einführung - Tutorial[/thread]

In dem folgenden Thread, findest entsprechende Möglichkeiten bei den Windows Forms:
[thread=261587]C# threading - Probleme - Thread[/thread]
 
Zuletzt bearbeitet:
kannst du mir mal ein Beispiel zusammenschustern?
Das ist jetzt sehr theoretisch...
Also müsste ich innerhalb von Pinger.cs Form1 nochmal aufrufen, die Werte ändern und dann mit MethodImplAttribut das Ding synchronisieren?
:confused:
 
Zuletzt bearbeitet:
Was Du hier machst ist ein statischer Methodenaufruf. Also über den Klassennamen. Da die Methode aber nicht statisch ist, kannst Du die Methode nur bei einem instanzierten Objekt aufrufen. Schau bitte mal in die Links, die ich gepostet habe.

Definiere in deiner Klasse Pinger ein Event ([thread=219377]Eigene Eventhandler .... - Thread[/thread]) und aboniere es in deinem Form. Der Klasse Pinger übergibst Du eine Referenz deines Forms (entweder als Property oder im Konstuktor) und invokst das Event dann auf dem Form (Control.Invoke). Du kannst hierfür als Typ Control verwenden, da Form von Control erbt. Als Beispiel kannst Dir dafür mein [post=1337449]Beispielprogramm[/post] anschauen.

Btw. Klassennamen solltest generell groß schreiben.
 
Okay.
Klassenname groß, Aufruf angepasst.
Jetzt sieht die Pinger.cs so aus:

Code:
using System;
using System.Collections.Generic;
using System.Net;
using System.Net.NetworkInformation;
using System.Text;
using System.Windows.Forms;

namespace idea
{
    class Pinger
    {
        private string host;
        public Pinger(string host_str)
        {
            host = host_str;
        }

        public delegate void PingFinishedEventHandler(object sender, string pinged_host);

        public event PingFinishedEventHandler PingFinished;

        public void do_ping()
        {
            try
            {
                Ping pingSender = new Ping();
                PingOptions options = new PingOptions();

                // Use the default Ttl value which is 128,
                // but change the fragmentation behavior.
                options.DontFragment = true;

                // Create a buffer of 32 bytes of data to be transmitted.
                string data = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
                byte[] buffer = Encoding.ASCII.GetBytes(data);
                int timeout = 120;
                PingReply reply = pingSender.Send(host, timeout, buffer, options);
                string message = "";
                if (reply.Status == IPStatus.Success)
                {
                    message += "Address: {0}" + reply.Address.ToString();
                    message += "\nRoundTrip time: {0}" + reply.RoundtripTime;
                    message += "\nTime to live: {0}" + reply.Optionsl;
                    message += "\nDon't fragment: {0}" + reply.Options.DontFragment;
                    message += "\nBuffer size: {0}" + reply.Buffer.Length;
                }
                System.Windows.Forms.MessageBox.Show(message);
            }
            catch
            {
                System.Windows.Forms.MessageBox.Show("PC aus.");
            }
            PingFinished(this, host);
            System.Threading.Thread.CurrentThread.Abort();
        }
    }
}

Also einen Eventhandler PingFinishedEventHandler erzeugt.

Hier die Methode in Form1.cs:
Code:
private void pingFinished(object sender, string pinged_host)
        {
            MessageBox.Show("Ping fertig.");
            //statusbarelemente unsichtbar
        }
und so abboniere ich es dann:
Code:
this.Load += new idea.Pinger.PingFinishedEventHandler(this.pingFinished);

Gibt aber eine Fehlermeldung (CS0029:Eine implizite Konvertierung vom Typ "idea.Pinger.PingFinishedEventHandler" in "System.EventHandler" ist nicht möglich)

Wie abboniere ich es richtig?
 
Zuletzt bearbeitet:
Also müsste ich innerhalb von Pinger.cs Form1 nochmal aufrufen, die Werte ändern und dann mit MethodImplAttribut das Ding synchronisieren?
:confused:
Der erste Teil meines Tutorials bezieht sich auch auf das allgemeine Multithreading.
Bei den Windows Forms ist das wieder anders, da Du hier keine Synchronisation in der Form benötigst. Es ist ja so, dass Design und Logik strikt voneinander getrennt werden müssen, damit der Code pfleg- und erweiterbar sowie als auch modular ist, damit man Funktionalitäten leicht einbinden oder extrahieren kann. Daraus ergibt sich, dass die Komponenten, welche die eigentliche Programmlogik beinhalten, nicht mit den Referenzen der Präsentationsobjekte interagieren, sondern ihre Stadi via Ereignissen bereit stellen. Die Ereignisse kannst dann auf den Threads der Präsentationsobjekte via Contol.Invoke aufrufen. Das hat mit dem MethodImplAttribut nichts zu tun, da es lediglich eine Methode sperrt aber nicht den Thread des Controls und der Inhalt trotzdem in dem Thread ausgeführt werden würde, der das Ereignis ausgelöst hat.
 
PHP, hat mit Managed Programming nichts zu tun. Das ist eine Scriptsprache und ist daher zu lernen nicht geeignet, da die inkonsistent ist und nicht nach den heutigen Paradigmen der Anwendungsentwicklung gestrickt ist. Und da PHP viele Dinge zulässt und kaum Kenntnisse vorraus setzt, um zB ein Hello World zu erzeugen, können sich zudem falsche bzw. schlechte Programmierstile bei dem Entwickler ausprägen.
Daher muss man bei dem Erlernen einer richtigen Programmiersprache wieder komplett von vorne Anfangen und sich alle Grundlagen erarbeiten, die dafür nötig sind. Angefangen bei Managed Programming, CLR, .NET, OOP, Typen, Datentypen, Operatoren, Windows Forms, UML, etc. Mit Java, C# oder VB.NET einzusteigen währe leider die bessere Wahl gewesen.
Ich würde Dir aber empfehlen dran zu bleiben, da Du einen Großteil des Wissens wieder in anderen Programmiersprachen und ergo besonders bei Scriptsprachen anwenden kannst. :)

//Edit: Wichtig: Das Ereignis, welches von deiner Klasse Ping ausgelöst wird, musst jetzt nur noch auf dem Form invoken, damit Du ordnungsgemäß auf dessen Steuerelemente zugreifen kannst. In diesen beiden Posts ist es beschrieben:
[post=1357223]AW: C# threading - Probleme - Post[/post]
[post=1357223]AW: C# threading - Probleme - Post[/post]

Btw: [thread=260892].NET Tutorials - Stickie[/thread]

Den Thread mal bitte als erledigt markieren, sofern Du keine weiteren Fragen hast. ;)
 
Zuletzt bearbeitet:
und so abboniere ich es dann:
Code:
this.Load += new idea.Pinger.PingFinishedEventHandler(this.pingFinished);
Gibt aber eine Fehlermeldung (CS0029:Eine implizite Konvertierung vom Typ "idea.Pinger.PingFinishedEventHandler" in "System.EventHandler" ist nicht möglich)

Wie abboniere ich es richtig?

Was ist damit?
Ist das dann richtig wenn ich es invoked habe?
 
Zuletzt bearbeitet:

Neue Beiträge

Zurück